3 * Object creation for the Mono runtime
6 * Miguel de Icaza (miguel@ximian.com)
7 * Paolo Molaro (lupus@ximian.com)
9 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10 * Copyright 2004-2011 Novell, Inc (http://www.novell.com)
11 * Copyright 2001 Xamarin Inc (http://www.xamarin.com)
12 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
21 #include <mono/metadata/mono-endian.h>
22 #include <mono/metadata/tabledefs.h>
23 #include <mono/metadata/tokentype.h>
24 #include <mono/metadata/loader.h>
25 #include <mono/metadata/object.h>
26 #include <mono/metadata/gc-internals.h>
27 #include <mono/metadata/exception.h>
28 #include <mono/metadata/exception-internals.h>
29 #include <mono/metadata/domain-internals.h>
30 #include "mono/metadata/metadata-internals.h"
31 #include "mono/metadata/class-internals.h"
32 #include <mono/metadata/assembly.h>
33 #include <mono/metadata/marshal.h>
34 #include "mono/metadata/debug-helpers.h"
35 #include <mono/metadata/threads.h>
36 #include <mono/metadata/threads-types.h>
37 #include <mono/metadata/environment.h>
38 #include "mono/metadata/profiler-private.h"
39 #include "mono/metadata/security-manager.h"
40 #include <mono/metadata/verify-internals.h>
41 #include <mono/metadata/reflection-internals.h>
42 #include <mono/metadata/w32event.h>
43 #include <mono/utils/strenc.h>
44 #include <mono/utils/mono-counters.h>
45 #include <mono/utils/mono-error-internals.h>
46 #include <mono/utils/mono-memory-model.h>
47 #include <mono/utils/checked-build.h>
48 #include <mono/utils/mono-threads.h>
49 #include <mono/utils/mono-threads-coop.h>
50 #include "cominterop.h"
51 #include <mono/utils/w32api.h>
54 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error);
57 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error);
60 free_main_args (void);
63 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error);
66 array_full_copy_unchecked_size (MonoArray *src, MonoArray *dest, MonoClass *klass, uintptr_t size);
69 class_get_virtual_method (MonoClass *klass, MonoMethod *method, gboolean is_proxy, MonoError *error);
71 /* Class lazy loading functions */
72 static GENERATE_GET_CLASS_WITH_CACHE (pointer, "System.Reflection", "Pointer")
73 static GENERATE_GET_CLASS_WITH_CACHE (remoting_services, "System.Runtime.Remoting", "RemotingServices")
74 static GENERATE_GET_CLASS_WITH_CACHE (unhandled_exception_event_args, "System", "UnhandledExceptionEventArgs")
75 static GENERATE_GET_CLASS_WITH_CACHE (sta_thread_attribute, "System", "STAThreadAttribute")
76 static GENERATE_GET_CLASS_WITH_CACHE (activation_services, "System.Runtime.Remoting.Activation", "ActivationServices")
79 #define ldstr_lock() mono_os_mutex_lock (&ldstr_section)
80 #define ldstr_unlock() mono_os_mutex_unlock (&ldstr_section)
81 static mono_mutex_t ldstr_section;
85 * mono_runtime_object_init:
86 * \param this_obj the object to initialize
87 * This function calls the zero-argument constructor (which must
88 * exist) for the given object.
91 mono_runtime_object_init (MonoObject *this_obj)
94 mono_runtime_object_init_checked (this_obj, &error);
95 mono_error_assert_ok (&error);
99 * mono_runtime_object_init_checked:
100 * \param this_obj the object to initialize
101 * \param error set on error.
102 * This function calls the zero-argument constructor (which must
103 * exist) for the given object and returns TRUE on success, or FALSE
104 * on error and sets \p error.
107 mono_runtime_object_init_checked (MonoObject *this_obj, MonoError *error)
109 MONO_REQ_GC_UNSAFE_MODE;
111 MonoMethod *method = NULL;
112 MonoClass *klass = this_obj->vtable->klass;
115 method = mono_class_get_method_from_name (klass, ".ctor", 0);
117 g_error ("Could not lookup zero argument constructor for class %s", mono_type_get_full_name (klass));
119 if (method->klass->valuetype)
120 this_obj = (MonoObject *)mono_object_unbox (this_obj);
122 mono_runtime_invoke_checked (method, this_obj, NULL, error);
123 return is_ok (error);
126 /* The pseudo algorithm for type initialization from the spec
127 Note it doesn't say anything about domains - only threads.
129 2. If the type is initialized you are done.
130 2.1. If the type is not yet initialized, try to take an
132 2.2. If successful, record this thread as responsible for
133 initializing the type and proceed to step 2.3.
134 2.2.1. If not, see whether this thread or any thread
135 waiting for this thread to complete already holds the lock.
136 2.2.2. If so, return since blocking would create a deadlock. This thread
137 will now see an incompletely initialized state for the type,
138 but no deadlock will arise.
139 2.2.3 If not, block until the type is initialized then return.
140 2.3 Initialize the parent type and then all interfaces implemented
142 2.4 Execute the type initialization code for this type.
143 2.5 Mark the type as initialized, release the initialization lock,
144 awaken any threads waiting for this type to be initialized,
151 MonoNativeThreadId initializing_tid;
152 guint32 waiting_count;
155 /* condvar used to wait for 'done' becoming TRUE */
157 } TypeInitializationLock;
159 /* for locking access to type_initialization_hash and blocked_thread_hash */
160 static MonoCoopMutex type_initialization_section;
163 mono_type_initialization_lock (void)
165 /* The critical sections protected by this lock in mono_runtime_class_init_full () can block */
166 mono_coop_mutex_lock (&type_initialization_section);
170 mono_type_initialization_unlock (void)
172 mono_coop_mutex_unlock (&type_initialization_section);
176 mono_type_init_lock (TypeInitializationLock *lock)
178 MONO_REQ_GC_NEUTRAL_MODE;
180 mono_coop_mutex_lock (&lock->mutex);
184 mono_type_init_unlock (TypeInitializationLock *lock)
186 mono_coop_mutex_unlock (&lock->mutex);
189 /* from vtable to lock */
190 static GHashTable *type_initialization_hash;
192 /* from thread id to thread id being waited on */
193 static GHashTable *blocked_thread_hash;
196 static MonoThread *main_thread;
198 /* Functions supplied by the runtime */
199 static MonoRuntimeCallbacks callbacks;
202 * mono_thread_set_main:
203 * \param thread thread to set as the main thread
204 * This function can be used to instruct the runtime to treat \p thread
205 * as the main thread, ie, the thread that would normally execute the \c Main
206 * method. This basically means that at the end of \p thread, the runtime will
207 * wait for the existing foreground threads to quit and other such details.
210 mono_thread_set_main (MonoThread *thread)
212 MONO_REQ_GC_UNSAFE_MODE;
214 static gboolean registered = FALSE;
217 MONO_GC_REGISTER_ROOT_SINGLE (main_thread, MONO_ROOT_SOURCE_THREADING, "main thread object");
221 main_thread = thread;
225 * mono_thread_get_main:
228 mono_thread_get_main (void)
230 MONO_REQ_GC_UNSAFE_MODE;
236 mono_type_initialization_init (void)
238 mono_coop_mutex_init_recursive (&type_initialization_section);
239 type_initialization_hash = g_hash_table_new (NULL, NULL);
240 blocked_thread_hash = g_hash_table_new (NULL, NULL);
241 mono_os_mutex_init_recursive (&ldstr_section);
242 mono_register_jit_icall (ves_icall_string_alloc, "ves_icall_string_alloc", mono_create_icall_signature ("object int"), FALSE);
246 mono_type_initialization_cleanup (void)
249 /* This is causing race conditions with
250 * mono_release_type_locks
252 mono_coop_mutex_destroy (&type_initialization_section);
253 g_hash_table_destroy (type_initialization_hash);
254 type_initialization_hash = NULL;
256 mono_os_mutex_destroy (&ldstr_section);
257 g_hash_table_destroy (blocked_thread_hash);
258 blocked_thread_hash = NULL;
264 * get_type_init_exception_for_vtable:
266 * Return the stored type initialization exception for VTABLE.
268 static MonoException*
269 get_type_init_exception_for_vtable (MonoVTable *vtable)
271 MONO_REQ_GC_UNSAFE_MODE;
274 MonoDomain *domain = vtable->domain;
275 MonoClass *klass = vtable->klass;
279 if (!vtable->init_failed)
280 g_error ("Trying to get the init exception for a non-failed vtable of class %s", mono_type_get_full_name (klass));
283 * If the initializing thread was rudely aborted, the exception is not stored
287 mono_domain_lock (domain);
288 if (domain->type_init_exception_hash)
289 ex = (MonoException *)mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
290 mono_domain_unlock (domain);
293 if (klass->name_space && *klass->name_space)
294 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
296 full_name = g_strdup (klass->name);
297 ex = mono_get_exception_type_initialization_checked (full_name, NULL, &error);
299 return_val_if_nok (&error, NULL);
306 * mono_runtime_class_init:
307 * \param vtable vtable that needs to be initialized
308 * This routine calls the class constructor for \p vtable.
311 mono_runtime_class_init (MonoVTable *vtable)
313 MONO_REQ_GC_UNSAFE_MODE;
316 mono_runtime_class_init_full (vtable, &error);
317 mono_error_assert_ok (&error);
321 * Returns TRUE if the lock was freed.
322 * LOCKING: Caller should hold type_initialization_lock.
325 unref_type_lock (TypeInitializationLock *lock)
327 --lock->waiting_count;
328 if (lock->waiting_count == 0) {
329 mono_coop_mutex_destroy (&lock->mutex);
330 mono_coop_cond_destroy (&lock->cond);
339 * mono_runtime_class_init_full:
340 * \param vtable that neeeds to be initialized
341 * \param error set on error
342 * \returns TRUE if class constructor \c .cctor has been initialized successfully, or FALSE otherwise and sets \p error.
345 mono_runtime_class_init_full (MonoVTable *vtable, MonoError *error)
347 MONO_REQ_GC_UNSAFE_MODE;
349 MonoMethod *method = NULL;
352 MonoDomain *domain = vtable->domain;
353 TypeInitializationLock *lock;
354 MonoNativeThreadId tid;
355 int do_initialization = 0;
356 MonoDomain *last_domain = NULL;
357 gboolean pending_tae = FALSE;
361 if (vtable->initialized)
364 klass = vtable->klass;
366 if (!klass->image->checked_module_cctor) {
367 mono_image_check_for_module_cctor (klass->image);
368 if (klass->image->has_module_cctor) {
369 MonoClass *module_klass;
370 MonoVTable *module_vtable;
372 module_klass = mono_class_get_checked (klass->image, MONO_TOKEN_TYPE_DEF | 1, error);
377 module_vtable = mono_class_vtable_full (vtable->domain, module_klass, error);
380 if (!mono_runtime_class_init_full (module_vtable, error))
384 method = mono_class_get_cctor (klass);
386 vtable->initialized = 1;
390 tid = mono_native_thread_id_get ();
393 * Due some preprocessing inside a global lock. If we are the first thread
394 * trying to initialize this class, create a separate lock+cond var, and
395 * acquire it before leaving the global lock. The other threads will wait
399 mono_type_initialization_lock ();
400 /* double check... */
401 if (vtable->initialized) {
402 mono_type_initialization_unlock ();
405 if (vtable->init_failed) {
406 mono_type_initialization_unlock ();
408 /* The type initialization already failed once, rethrow the same exception */
409 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
412 lock = (TypeInitializationLock *)g_hash_table_lookup (type_initialization_hash, vtable);
414 /* This thread will get to do the initialization */
415 if (mono_domain_get () != domain) {
416 /* Transfer into the target domain */
417 last_domain = mono_domain_get ();
418 if (!mono_domain_set (domain, FALSE)) {
419 vtable->initialized = 1;
420 mono_type_initialization_unlock ();
421 mono_error_set_exception_instance (error, mono_get_exception_appdomain_unloaded ());
425 lock = (TypeInitializationLock *)g_malloc0 (sizeof (TypeInitializationLock));
426 mono_coop_mutex_init_recursive (&lock->mutex);
427 mono_coop_cond_init (&lock->cond);
428 lock->initializing_tid = tid;
429 lock->waiting_count = 1;
431 g_hash_table_insert (type_initialization_hash, vtable, lock);
432 do_initialization = 1;
435 TypeInitializationLock *pending_lock;
437 if (mono_native_thread_id_equals (lock->initializing_tid, tid)) {
438 mono_type_initialization_unlock ();
441 /* see if the thread doing the initialization is already blocked on this thread */
442 gboolean is_blocked = TRUE;
443 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (lock->initializing_tid));
444 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
445 if (mono_native_thread_id_equals (pending_lock->initializing_tid, tid)) {
446 if (!pending_lock->done) {
447 mono_type_initialization_unlock ();
450 /* the thread doing the initialization is blocked on this thread,
451 but on a lock that has already been freed. It just hasn't got
457 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (pending_lock->initializing_tid));
459 ++lock->waiting_count;
460 /* record the fact that we are waiting on the initializing thread */
462 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
464 mono_type_initialization_unlock ();
466 if (do_initialization) {
467 MonoException *exc = NULL;
469 /* We are holding the per-vtable lock, do the actual initialization */
471 mono_threads_begin_abort_protected_block ();
472 mono_runtime_try_invoke (method, NULL, NULL, (MonoObject**) &exc, error);
473 mono_threads_end_abort_protected_block ();
475 //exception extracted, error will be set to the right value later
476 if (exc == NULL && !mono_error_ok (error))//invoking failed but exc was not set
477 exc = mono_error_convert_to_exception (error);
479 mono_error_cleanup (error);
483 /* If the initialization failed, mark the class as unusable. */
484 /* Avoid infinite loops */
486 (klass->image == mono_defaults.corlib &&
487 !strcmp (klass->name_space, "System") &&
488 !strcmp (klass->name, "TypeInitializationException")))) {
489 vtable->init_failed = 1;
491 if (klass->name_space && *klass->name_space)
492 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
494 full_name = g_strdup (klass->name);
496 MonoException *exc_to_throw = mono_get_exception_type_initialization_checked (full_name, exc, error);
499 mono_error_assert_ok (error); //We can't recover from this, no way to fail a type we can't alloc a failure.
502 * Store the exception object so it could be thrown on subsequent
505 mono_domain_lock (domain);
506 if (!domain->type_init_exception_hash)
507 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");
508 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
509 mono_domain_unlock (domain);
513 mono_domain_set (last_domain, TRUE);
515 /* Signal to the other threads that we are done */
516 mono_type_init_lock (lock);
518 mono_coop_cond_broadcast (&lock->cond);
519 mono_type_init_unlock (lock);
522 * This can happen if the cctor self-aborts. We need to reactivate tae
523 * (next interruption checkpoint will throw it) and make sure we won't
524 * throw tie for the type.
526 if (exc && mono_object_class (exc) == mono_defaults.threadabortexception_class) {
528 mono_thread_resume_interruption (FALSE);
531 /* this just blocks until the initializing thread is done */
532 mono_type_init_lock (lock);
534 mono_coop_cond_wait (&lock->cond, &lock->mutex);
535 mono_type_init_unlock (lock);
538 /* Do cleanup and setting vtable->initialized inside the global lock again */
539 mono_type_initialization_lock ();
540 if (!do_initialization)
541 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
542 gboolean deleted = unref_type_lock (lock);
544 g_hash_table_remove (type_initialization_hash, vtable);
545 /* Have to set this here since we check it inside the global lock */
546 if (do_initialization && !vtable->init_failed)
547 vtable->initialized = 1;
548 mono_type_initialization_unlock ();
550 /* If vtable init fails because of TAE, we don't throw TIE, only the TAE */
551 if (vtable->init_failed && !pending_tae) {
552 /* Either we were the initializing thread or we waited for the initialization */
553 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
560 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
562 MONO_REQ_GC_NEUTRAL_MODE;
564 MonoVTable *vtable = (MonoVTable*)key;
566 TypeInitializationLock *lock = (TypeInitializationLock*) value;
567 if (mono_native_thread_id_equals (lock->initializing_tid, MONO_UINT_TO_NATIVE_THREAD_ID (GPOINTER_TO_UINT (user))) && !lock->done) {
570 * Have to set this since it cannot be set by the normal code in
571 * mono_runtime_class_init (). In this case, the exception object is not stored,
572 * and get_type_init_exception_for_class () needs to be aware of this.
574 mono_type_init_lock (lock);
575 vtable->init_failed = 1;
576 mono_coop_cond_broadcast (&lock->cond);
577 mono_type_init_unlock (lock);
578 gboolean deleted = unref_type_lock (lock);
586 mono_release_type_locks (MonoInternalThread *thread)
588 MONO_REQ_GC_UNSAFE_MODE;
590 mono_type_initialization_lock ();
591 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, GUINT_TO_POINTER (thread->tid));
592 mono_type_initialization_unlock ();
595 #ifndef DISABLE_REMOTING
598 create_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error)
600 if (!callbacks.create_remoting_trampoline)
601 g_error ("remoting not installed");
602 return callbacks.create_remoting_trampoline (domain, method, target, error);
607 static MonoImtTrampolineBuilder imt_trampoline_builder;
608 static gboolean always_build_imt_trampolines;
610 #if (MONO_IMT_SIZE > 32)
611 #error "MONO_IMT_SIZE cannot be larger than 32"
615 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
617 memcpy (&callbacks, cbs, sizeof (*cbs));
620 MonoRuntimeCallbacks*
621 mono_get_runtime_callbacks (void)
627 mono_install_imt_trampoline_builder (MonoImtTrampolineBuilder func)
629 imt_trampoline_builder = func;
633 mono_set_always_build_imt_trampolines (gboolean value)
635 always_build_imt_trampolines = value;
639 * mono_compile_method:
640 * \param method The method to compile.
641 * This JIT-compiles the method, and returns the pointer to the native code
645 mono_compile_method (MonoMethod *method)
648 gpointer result = mono_compile_method_checked (method, &error);
649 mono_error_cleanup (&error);
654 * mono_compile_method_checked:
655 * \param method The method to compile.
656 * \param error set on error.
657 * This JIT-compiles the method, and returns the pointer to the native code
658 * produced. On failure returns NULL and sets \p error.
661 mono_compile_method_checked (MonoMethod *method, MonoError *error)
665 MONO_REQ_GC_NEUTRAL_MODE
669 g_assert (callbacks.compile_method);
670 res = callbacks.compile_method (method, error);
675 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper, MonoError *error)
679 MONO_REQ_GC_NEUTRAL_MODE;
682 res = callbacks.create_jump_trampoline (domain, method, add_sync_wrapper, error);
687 mono_runtime_create_delegate_trampoline (MonoClass *klass)
689 MONO_REQ_GC_NEUTRAL_MODE
691 g_assert (callbacks.create_delegate_trampoline);
692 return callbacks.create_delegate_trampoline (mono_domain_get (), klass);
696 * mono_runtime_free_method:
697 * \param domain domain where the method is hosted
698 * \param method method to release
699 * This routine is invoked to free the resources associated with
700 * a method that has been JIT compiled. This is used to discard
701 * methods that were used only temporarily (for example, used in marshalling)
704 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
706 MONO_REQ_GC_NEUTRAL_MODE
708 if (callbacks.free_method)
709 callbacks.free_method (domain, method);
711 mono_method_clear_object (domain, method);
713 mono_free_method (method);
717 * The vtables in the root appdomain are assumed to be reachable by other
718 * roots, and we don't use typed allocation in the other domains.
721 /* The sync block is no longer a GC pointer */
722 #define GC_HEADER_BITMAP (0)
724 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
727 compute_class_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
729 MONO_REQ_GC_NEUTRAL_MODE;
731 MonoClassField *field;
737 max_size = mono_class_data_size (klass) / sizeof (gpointer);
739 max_size = klass->instance_size / sizeof (gpointer);
740 if (max_size > size) {
741 g_assert (offset <= 0);
742 bitmap = (gsize *)g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
746 /* An Ephemeron cannot be marked by sgen */
747 if (mono_gc_is_moving () && !static_fields && klass->image == mono_defaults.corlib && !strcmp ("Ephemeron", klass->name)) {
749 memset (bitmap, 0, size / 8);
753 for (p = klass; p != NULL; p = p->parent) {
754 gpointer iter = NULL;
755 while ((field = mono_class_get_fields (p, &iter))) {
759 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
761 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
764 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
767 /* FIXME: should not happen, flag as type load error */
768 if (field->type->byref)
771 if (static_fields && field->offset == -1)
775 pos = field->offset / sizeof (gpointer);
778 type = mono_type_get_underlying_type (field->type);
779 switch (type->type) {
783 case MONO_TYPE_FNPTR:
785 case MONO_TYPE_STRING:
786 case MONO_TYPE_SZARRAY:
787 case MONO_TYPE_CLASS:
788 case MONO_TYPE_OBJECT:
789 case MONO_TYPE_ARRAY:
790 g_assert ((field->offset % sizeof(gpointer)) == 0);
792 g_assert (pos < size || pos <= max_size);
793 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
794 *max_set = MAX (*max_set, pos);
796 case MONO_TYPE_GENERICINST:
797 if (!mono_type_generic_inst_is_valuetype (type)) {
798 g_assert ((field->offset % sizeof(gpointer)) == 0);
800 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
801 *max_set = MAX (*max_set, pos);
806 case MONO_TYPE_VALUETYPE: {
807 MonoClass *fclass = mono_class_from_mono_type (field->type);
808 if (fclass->has_references) {
809 /* remove the object header */
810 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
824 case MONO_TYPE_BOOLEAN:
828 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
839 * mono_class_compute_bitmap:
841 * Mono internal function to compute a bitmap of reference fields in a class.
844 mono_class_compute_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
846 MONO_REQ_GC_NEUTRAL_MODE;
848 return compute_class_bitmap (klass, bitmap, size, offset, max_set, static_fields);
853 * similar to the above, but sets the bits in the bitmap for any non-ref field
854 * and ignores static fields
857 compute_class_non_ref_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset)
859 MonoClassField *field;
864 max_size = class->instance_size / sizeof (gpointer);
865 if (max_size >= size) {
866 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
869 for (p = class; p != NULL; p = p->parent) {
870 gpointer iter = NULL;
871 while ((field = mono_class_get_fields (p, &iter))) {
874 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
876 /* FIXME: should not happen, flag as type load error */
877 if (field->type->byref)
880 pos = field->offset / sizeof (gpointer);
883 type = mono_type_get_underlying_type (field->type);
884 switch (type->type) {
885 #if SIZEOF_VOID_P == 8
889 case MONO_TYPE_FNPTR:
894 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
895 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
896 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
899 #if SIZEOF_VOID_P == 4
903 case MONO_TYPE_FNPTR:
908 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
909 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
910 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
916 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
917 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
918 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
921 case MONO_TYPE_BOOLEAN:
924 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
926 case MONO_TYPE_STRING:
927 case MONO_TYPE_SZARRAY:
928 case MONO_TYPE_CLASS:
929 case MONO_TYPE_OBJECT:
930 case MONO_TYPE_ARRAY:
932 case MONO_TYPE_GENERICINST:
933 if (!mono_type_generic_inst_is_valuetype (type)) {
938 case MONO_TYPE_VALUETYPE: {
939 MonoClass *fclass = mono_class_from_mono_type (field->type);
940 /* remove the object header */
941 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
945 g_assert_not_reached ();
954 * mono_class_insecure_overlapping:
955 * check if a class with explicit layout has references and non-references
956 * fields overlapping.
958 * Returns: TRUE if it is insecure to load the type.
961 mono_class_insecure_overlapping (MonoClass *klass)
965 gsize default_bitmap [4] = {0};
967 gsize default_nrbitmap [4] = {0};
968 int i, insecure = FALSE;
971 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
972 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
974 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
975 int idx = i % (sizeof (bitmap [0]) * 8);
976 if (bitmap [idx] & nrbitmap [idx]) {
981 if (bitmap != default_bitmap)
983 if (nrbitmap != default_nrbitmap)
986 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
994 ves_icall_string_alloc (int length)
997 MonoString *str = mono_string_new_size_checked (mono_domain_get (), length, &error);
998 mono_error_set_pending_exception (&error);
1003 /* LOCKING: Acquires the loader lock */
1005 mono_class_compute_gc_descriptor (MonoClass *klass)
1007 MONO_REQ_GC_NEUTRAL_MODE;
1011 gsize default_bitmap [4] = {0};
1012 MonoGCDescriptor gc_descr;
1015 mono_class_init (klass);
1017 if (klass->gc_descr_inited)
1020 bitmap = default_bitmap;
1021 if (klass == mono_defaults.string_class) {
1022 gc_descr = mono_gc_make_descr_for_string (bitmap, 2);
1023 } else if (klass->rank) {
1024 mono_class_compute_gc_descriptor (klass->element_class);
1025 if (MONO_TYPE_IS_REFERENCE (&klass->element_class->byval_arg)) {
1027 gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
1028 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1029 class->name_space, class->name);*/
1031 /* remove the object header */
1032 bitmap = compute_class_bitmap (klass->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
1033 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));
1034 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1035 class->name_space, class->name);*/
1036 if (bitmap != default_bitmap)
1040 /*static int count = 0;
1043 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1044 gc_descr = mono_gc_make_descr_for_object (bitmap, max_set + 1, klass->instance_size);
1046 if (class->gc_descr == MONO_GC_DESCRIPTOR_NULL)
1047 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
1049 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
1050 if (bitmap != default_bitmap)
1054 /* Publish the data */
1055 mono_loader_lock ();
1056 klass->gc_descr = gc_descr;
1057 mono_memory_barrier ();
1058 klass->gc_descr_inited = TRUE;
1059 mono_loader_unlock ();
1063 * field_is_special_static:
1064 * @fklass: The MonoClass to look up.
1065 * @field: The MonoClassField describing the field.
1067 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1068 * SPECIAL_STATIC_NONE otherwise.
1071 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1073 MONO_REQ_GC_NEUTRAL_MODE;
1076 MonoCustomAttrInfo *ainfo;
1078 ainfo = mono_custom_attrs_from_field_checked (fklass, field, &error);
1079 mono_error_cleanup (&error); /* FIXME don't swallow the error? */
1082 for (i = 0; i < ainfo->num_attrs; ++i) {
1083 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1084 if (klass->image == mono_defaults.corlib) {
1085 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1086 mono_custom_attrs_free (ainfo);
1087 return SPECIAL_STATIC_THREAD;
1089 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1090 mono_custom_attrs_free (ainfo);
1091 return SPECIAL_STATIC_CONTEXT;
1095 mono_custom_attrs_free (ainfo);
1096 return SPECIAL_STATIC_NONE;
1099 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1100 #define mix(a,b,c) { \
1101 a -= c; a ^= rot(c, 4); c += b; \
1102 b -= a; b ^= rot(a, 6); a += c; \
1103 c -= b; c ^= rot(b, 8); b += a; \
1104 a -= c; a ^= rot(c,16); c += b; \
1105 b -= a; b ^= rot(a,19); a += c; \
1106 c -= b; c ^= rot(b, 4); b += a; \
1108 #define final(a,b,c) { \
1109 c ^= b; c -= rot(b,14); \
1110 a ^= c; a -= rot(c,11); \
1111 b ^= a; b -= rot(a,25); \
1112 c ^= b; c -= rot(b,16); \
1113 a ^= c; a -= rot(c,4); \
1114 b ^= a; b -= rot(a,14); \
1115 c ^= b; c -= rot(b,24); \
1119 * mono_method_get_imt_slot:
1121 * The IMT slot is embedded into AOTed code, so this must return the same value
1122 * for the same method across all executions. This means:
1123 * - pointers shouldn't be used as hash values.
1124 * - mono_metadata_str_hash () should be used for hashing strings.
1127 mono_method_get_imt_slot (MonoMethod *method)
1129 MONO_REQ_GC_NEUTRAL_MODE;
1131 MonoMethodSignature *sig;
1133 guint32 *hashes_start, *hashes;
1137 /* This can be used to stress tests the collision code */
1141 * We do this to simplify generic sharing. It will hurt
1142 * performance in cases where a class implements two different
1143 * instantiations of the same generic interface.
1144 * The code in build_imt_slots () depends on this.
1146 if (method->is_inflated)
1147 method = ((MonoMethodInflated*)method)->declaring;
1149 sig = mono_method_signature (method);
1150 hashes_count = sig->param_count + 4;
1151 hashes_start = (guint32 *)g_malloc (hashes_count * sizeof (guint32));
1152 hashes = hashes_start;
1154 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1155 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1156 method->klass->name_space, method->klass->name, method->name);
1159 /* Initialize hashes */
1160 hashes [0] = mono_metadata_str_hash (method->klass->name);
1161 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1162 hashes [2] = mono_metadata_str_hash (method->name);
1163 hashes [3] = mono_metadata_type_hash (sig->ret);
1164 for (i = 0; i < sig->param_count; i++) {
1165 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1168 /* Setup internal state */
1169 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1171 /* Handle most of the hashes */
1172 while (hashes_count > 3) {
1181 /* Handle the last 3 hashes (all the case statements fall through) */
1182 switch (hashes_count) {
1183 case 3 : c += hashes [2];
1184 case 2 : b += hashes [1];
1185 case 1 : a += hashes [0];
1187 case 0: /* nothing left to add */
1191 g_free (hashes_start);
1192 /* Report the result */
1193 return c % MONO_IMT_SIZE;
1202 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1203 MONO_REQ_GC_NEUTRAL_MODE;
1205 guint32 imt_slot = mono_method_get_imt_slot (method);
1206 MonoImtBuilderEntry *entry;
1208 if (slot_num >= 0 && imt_slot != slot_num) {
1209 /* we build just a single imt slot and this is not it */
1213 entry = (MonoImtBuilderEntry *)g_malloc0 (sizeof (MonoImtBuilderEntry));
1214 entry->key = method;
1215 entry->value.vtable_slot = vtable_slot;
1216 entry->next = imt_builder [imt_slot];
1217 if (imt_builder [imt_slot] != NULL) {
1218 entry->children = imt_builder [imt_slot]->children + 1;
1219 if (entry->children == 1) {
1220 mono_stats.imt_slots_with_collisions++;
1221 *imt_collisions_bitmap |= (1 << imt_slot);
1224 entry->children = 0;
1225 mono_stats.imt_used_slots++;
1227 imt_builder [imt_slot] = entry;
1230 char *method_name = mono_method_full_name (method, TRUE);
1231 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1232 method, method_name, imt_slot, vtable_slot, entry->children);
1233 g_free (method_name);
1240 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1242 MonoMethod *method = e->key;
1243 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1247 method->klass->name_space,
1248 method->klass->name,
1251 printf (" * %s: NULL\n", message);
1257 compare_imt_builder_entries (const void *p1, const void *p2) {
1258 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1259 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1261 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1265 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1267 MONO_REQ_GC_NEUTRAL_MODE;
1269 int count = end - start;
1270 int chunk_start = out_array->len;
1273 for (i = start; i < end; ++i) {
1274 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1275 item->key = sorted_array [i]->key;
1276 item->value = sorted_array [i]->value;
1277 item->has_target_code = sorted_array [i]->has_target_code;
1278 item->is_equals = TRUE;
1280 item->check_target_idx = out_array->len + 1;
1282 item->check_target_idx = 0;
1283 g_ptr_array_add (out_array, item);
1286 int middle = start + count / 2;
1287 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1289 item->key = sorted_array [middle]->key;
1290 item->is_equals = FALSE;
1291 g_ptr_array_add (out_array, item);
1292 imt_emit_ir (sorted_array, start, middle, out_array);
1293 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1299 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1300 MONO_REQ_GC_NEUTRAL_MODE;
1302 int number_of_entries = entries->children + 1;
1303 MonoImtBuilderEntry **sorted_array = (MonoImtBuilderEntry **)g_malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1304 GPtrArray *result = g_ptr_array_new ();
1305 MonoImtBuilderEntry *current_entry;
1308 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1309 sorted_array [i] = current_entry;
1311 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1313 /*for (i = 0; i < number_of_entries; i++) {
1314 print_imt_entry (" sorted array:", sorted_array [i], i);
1317 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1319 g_free (sorted_array);
1324 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1326 MONO_REQ_GC_NEUTRAL_MODE;
1328 if (imt_builder_entry != NULL) {
1329 if (imt_builder_entry->children == 0 && !fail_tramp && !always_build_imt_trampolines) {
1330 /* No collision, return the vtable slot contents */
1331 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1333 /* Collision, build the trampoline */
1334 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1337 result = imt_trampoline_builder (vtable, domain,
1338 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1339 for (i = 0; i < imt_ir->len; ++i)
1340 g_free (g_ptr_array_index (imt_ir, i));
1341 g_ptr_array_free (imt_ir, TRUE);
1353 static MonoImtBuilderEntry*
1354 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1357 * LOCKING: requires the loader and domain locks.
1361 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1363 MONO_REQ_GC_NEUTRAL_MODE;
1367 guint32 imt_collisions_bitmap = 0;
1368 MonoImtBuilderEntry **imt_builder = (MonoImtBuilderEntry **)g_calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1369 int method_count = 0;
1370 gboolean record_method_count_for_max_collisions = FALSE;
1371 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1374 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1376 for (i = 0; i < klass->interface_offsets_count; ++i) {
1377 MonoClass *iface = klass->interfaces_packed [i];
1378 int interface_offset = klass->interface_offsets_packed [i];
1379 int method_slot_in_interface, vt_slot;
1381 if (mono_class_has_variant_generic_params (iface))
1382 has_variant_iface = TRUE;
1384 mono_class_setup_methods (iface);
1385 vt_slot = interface_offset;
1386 int mcount = mono_class_get_method_count (iface);
1387 for (method_slot_in_interface = 0; method_slot_in_interface < mcount; method_slot_in_interface++) {
1390 if (slot_num >= 0 && mono_class_is_ginst (iface)) {
1392 * The imt slot of the method is the same as for its declaring method,
1393 * see the comment in mono_method_get_imt_slot (), so we can
1394 * avoid inflating methods which will be discarded by
1395 * add_imt_builder_entry anyway.
1397 method = mono_class_get_method_by_index (mono_class_get_generic_class (iface)->container_class, method_slot_in_interface);
1398 if (mono_method_get_imt_slot (method) != slot_num) {
1403 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1404 if (method->is_generic) {
1405 has_generic_virtual = TRUE;
1410 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1411 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1416 if (extra_interfaces) {
1417 int interface_offset = klass->vtable_size;
1419 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1420 MonoClass* iface = (MonoClass *)list_item->data;
1421 int method_slot_in_interface;
1422 int mcount = mono_class_get_method_count (iface);
1423 for (method_slot_in_interface = 0; method_slot_in_interface < mcount; method_slot_in_interface++) {
1424 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1426 if (method->is_generic)
1427 has_generic_virtual = TRUE;
1428 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1430 interface_offset += mcount;
1433 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1434 /* overwrite the imt slot only if we're building all the entries or if
1435 * we're building this specific one
1437 if (slot_num < 0 || i == slot_num) {
1438 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1441 if (imt_builder [i]) {
1442 MonoImtBuilderEntry *entry;
1444 /* Link entries with imt_builder [i] */
1445 for (entry = entries; entry->next; entry = entry->next) {
1447 MonoMethod *method = (MonoMethod*)entry->key;
1448 char *method_name = mono_method_full_name (method, TRUE);
1449 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1450 g_free (method_name);
1453 entry->next = imt_builder [i];
1454 entries->children += imt_builder [i]->children + 1;
1456 imt_builder [i] = entries;
1459 if (has_generic_virtual || has_variant_iface) {
1461 * There might be collisions later when the the trampoline is expanded.
1463 imt_collisions_bitmap |= (1 << i);
1466 * The IMT trampoline might be called with an instance of one of the
1467 * generic virtual methods, so has to fallback to the IMT trampoline.
1469 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline (vt, i));
1471 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1474 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1478 if (imt_builder [i] != NULL) {
1479 int methods_in_slot = imt_builder [i]->children + 1;
1480 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1481 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1482 record_method_count_for_max_collisions = TRUE;
1484 method_count += methods_in_slot;
1488 mono_stats.imt_number_of_methods += method_count;
1489 if (record_method_count_for_max_collisions) {
1490 mono_stats.imt_method_count_when_max_collisions = method_count;
1493 for (i = 0; i < MONO_IMT_SIZE; i++) {
1494 MonoImtBuilderEntry* entry = imt_builder [i];
1495 while (entry != NULL) {
1496 MonoImtBuilderEntry* next = entry->next;
1501 g_free (imt_builder);
1502 /* we OR the bitmap since we may build just a single imt slot at a time */
1503 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1507 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1508 MONO_REQ_GC_NEUTRAL_MODE;
1510 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1514 * mono_vtable_build_imt_slot:
1515 * \param vtable virtual object table struct
1516 * \param imt_slot slot in the IMT table
1517 * Fill the given \p imt_slot in the IMT table of \p vtable with
1518 * a trampoline or a trampoline for the case of collisions.
1519 * This is part of the internal mono API.
1520 * LOCKING: Take the domain lock.
1523 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1525 MONO_REQ_GC_NEUTRAL_MODE;
1527 gpointer *imt = (gpointer*)vtable;
1528 imt -= MONO_IMT_SIZE;
1529 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1531 /* no support for extra interfaces: the proxy objects will need
1532 * to build the complete IMT
1533 * Update and heck needs to ahppen inside the proper domain lock, as all
1534 * the changes made to a MonoVTable.
1536 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1537 mono_domain_lock (vtable->domain);
1538 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1539 if (!callbacks.imt_entry_inited (vtable, imt_slot))
1540 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1541 mono_domain_unlock (vtable->domain);
1542 mono_loader_unlock ();
1545 #define THUNK_THRESHOLD 10
1548 * mono_method_alloc_generic_virtual_trampoline:
1549 * \param domain a domain
1550 * \param size size in bytes
1551 * Allocs \p size bytes to be used for the code of a generic virtual
1552 * trampoline. It's either allocated from the domain's code manager or
1553 * reused from a previously invalidated piece.
1554 * LOCKING: The domain lock must be held.
1557 mono_method_alloc_generic_virtual_trampoline (MonoDomain *domain, int size)
1559 MONO_REQ_GC_NEUTRAL_MODE;
1561 static gboolean inited = FALSE;
1562 static int generic_virtual_trampolines_size = 0;
1565 mono_counters_register ("Generic virtual trampoline bytes",
1566 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_trampolines_size);
1569 generic_virtual_trampolines_size += size;
1571 return mono_domain_code_reserve (domain, size);
1574 typedef struct _GenericVirtualCase {
1578 struct _GenericVirtualCase *next;
1579 } GenericVirtualCase;
1582 * get_generic_virtual_entries:
1584 * Return IMT entries for the generic virtual method instances and
1585 * variant interface methods for vtable slot
1588 static MonoImtBuilderEntry*
1589 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1591 MONO_REQ_GC_NEUTRAL_MODE;
1593 GenericVirtualCase *list;
1594 MonoImtBuilderEntry *entries;
1596 mono_domain_lock (domain);
1597 if (!domain->generic_virtual_cases)
1598 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1600 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1603 for (; list; list = list->next) {
1604 MonoImtBuilderEntry *entry;
1606 if (list->count < THUNK_THRESHOLD)
1609 entry = g_new0 (MonoImtBuilderEntry, 1);
1610 entry->key = list->method;
1611 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1612 entry->has_target_code = 1;
1614 entry->children = entries->children + 1;
1615 entry->next = entries;
1619 mono_domain_unlock (domain);
1621 /* FIXME: Leaking memory ? */
1626 * \param domain a domain
1627 * \param vtable_slot pointer to the vtable slot
1628 * \param method the inflated generic virtual method
1629 * \param code the method's code
1631 * Registers a call via unmanaged code to a generic virtual method
1632 * instantiation or variant interface method. If the number of calls reaches a threshold
1633 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1634 * virtual method trampoline.
1637 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1638 gpointer *vtable_slot,
1639 MonoMethod *method, gpointer code)
1641 MONO_REQ_GC_NEUTRAL_MODE;
1643 static gboolean inited = FALSE;
1644 static int num_added = 0;
1645 static int num_freed = 0;
1647 GenericVirtualCase *gvc, *list;
1648 MonoImtBuilderEntry *entries;
1652 mono_domain_lock (domain);
1653 if (!domain->generic_virtual_cases)
1654 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1657 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1658 mono_counters_register ("Freed IMT trampolines", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_freed);
1662 /* Check whether the case was already added */
1663 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1666 if (gvc->method == method)
1671 /* If not found, make a new one */
1673 gvc = (GenericVirtualCase *)mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1674 gvc->method = method;
1677 gvc->next = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1679 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1684 if (++gvc->count == THUNK_THRESHOLD) {
1685 gpointer *old_thunk = (void **)*vtable_slot;
1686 gpointer vtable_trampoline = NULL;
1687 gpointer imt_trampoline = NULL;
1689 if ((gpointer)vtable_slot < (gpointer)vtable) {
1690 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1691 int imt_slot = MONO_IMT_SIZE + displacement;
1693 /* Force the rebuild of the trampoline at the next call */
1694 imt_trampoline = callbacks.get_imt_trampoline (vtable, imt_slot);
1695 *vtable_slot = imt_trampoline;
1697 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline (vtable, (gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1699 entries = get_generic_virtual_entries (domain, vtable_slot);
1701 sorted = imt_sort_slot_entries (entries);
1703 *vtable_slot = imt_trampoline_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1707 MonoImtBuilderEntry *next = entries->next;
1712 for (i = 0; i < sorted->len; ++i)
1713 g_free (g_ptr_array_index (sorted, i));
1714 g_ptr_array_free (sorted, TRUE);
1716 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1721 mono_domain_unlock (domain);
1724 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error);
1727 * mono_class_vtable:
1728 * \param domain the application domain
1729 * \param class the class to initialize
1730 * VTables are domain specific because we create domain specific code, and
1731 * they contain the domain specific static class data.
1732 * On failure, NULL is returned, and \c class->exception_type is set.
1735 mono_class_vtable (MonoDomain *domain, MonoClass *klass)
1738 MonoVTable* vtable = mono_class_vtable_full (domain, klass, &error);
1739 mono_error_cleanup (&error);
1744 * mono_class_vtable_full:
1745 * \param domain the application domain
1746 * \param class the class to initialize
1747 * \param error set on failure.
1748 * VTables are domain specific because we create domain specific code, and
1749 * they contain the domain specific static class data.
1752 mono_class_vtable_full (MonoDomain *domain, MonoClass *klass, MonoError *error)
1754 MONO_REQ_GC_UNSAFE_MODE;
1756 MonoClassRuntimeInfo *runtime_info;
1762 if (mono_class_has_failure (klass)) {
1763 mono_error_set_for_class_failure (error, klass);
1767 /* this check can be inlined in jitted code, too */
1768 runtime_info = klass->runtime_info;
1769 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1770 return runtime_info->domain_vtables [domain->domain_id];
1771 return mono_class_create_runtime_vtable (domain, klass, error);
1775 * mono_class_try_get_vtable:
1776 * \param domain the application domain
1777 * \param class the class to initialize
1778 * This function tries to get the associated vtable from \p class if
1779 * it was already created.
1782 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *klass)
1784 MONO_REQ_GC_NEUTRAL_MODE;
1786 MonoClassRuntimeInfo *runtime_info;
1790 runtime_info = klass->runtime_info;
1791 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1792 return runtime_info->domain_vtables [domain->domain_id];
1797 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1799 MONO_REQ_GC_NEUTRAL_MODE;
1801 size_t alloc_offset;
1804 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1805 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1806 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1808 if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1809 g_assert ((imt_table_bytes & 7) == 4);
1816 return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1820 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error)
1822 MONO_REQ_GC_UNSAFE_MODE;
1825 MonoClassRuntimeInfo *runtime_info, *old_info;
1826 MonoClassField *field;
1828 int i, vtable_slots;
1829 size_t imt_table_bytes;
1831 guint32 vtable_size, class_size;
1833 gpointer *interface_offsets;
1837 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1838 mono_domain_lock (domain);
1839 runtime_info = klass->runtime_info;
1840 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1841 mono_domain_unlock (domain);
1842 mono_loader_unlock ();
1843 return runtime_info->domain_vtables [domain->domain_id];
1845 if (!klass->inited || mono_class_has_failure (klass)) {
1846 if (!mono_class_init (klass) || mono_class_has_failure (klass)) {
1847 mono_domain_unlock (domain);
1848 mono_loader_unlock ();
1849 mono_error_set_for_class_failure (error, klass);
1854 /* Array types require that their element type be valid*/
1855 if (klass->byval_arg.type == MONO_TYPE_ARRAY || klass->byval_arg.type == MONO_TYPE_SZARRAY) {
1856 MonoClass *element_class = klass->element_class;
1857 if (!element_class->inited)
1858 mono_class_init (element_class);
1860 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1861 if (!mono_class_has_failure (element_class) && !element_class->vtable_size)
1862 mono_class_setup_vtable (element_class);
1864 if (mono_class_has_failure (element_class)) {
1865 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1866 if (!mono_class_has_failure (klass))
1867 mono_class_set_type_load_failure (klass, "");
1868 mono_domain_unlock (domain);
1869 mono_loader_unlock ();
1870 mono_error_set_for_class_failure (error, klass);
1876 * For some classes, mono_class_init () already computed klass->vtable_size, and
1877 * that is all that is needed because of the vtable trampolines.
1879 if (!klass->vtable_size)
1880 mono_class_setup_vtable (klass);
1882 if (mono_class_is_ginst (klass) && !klass->vtable)
1883 mono_class_check_vtable_constraints (klass, NULL);
1885 /* Initialize klass->has_finalize */
1886 mono_class_has_finalizer (klass);
1888 if (mono_class_has_failure (klass)) {
1889 mono_domain_unlock (domain);
1890 mono_loader_unlock ();
1891 mono_error_set_for_class_failure (error, klass);
1895 vtable_slots = klass->vtable_size;
1896 /* we add an additional vtable slot to store the pointer to static field data only when needed */
1897 class_size = mono_class_data_size (klass);
1901 if (klass->interface_offsets_count) {
1902 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1903 mono_stats.imt_number_of_tables++;
1904 mono_stats.imt_tables_size += imt_table_bytes;
1906 imt_table_bytes = 0;
1909 vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
1911 mono_stats.used_class_count++;
1912 mono_stats.class_vtable_size += vtable_size;
1914 interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
1915 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1916 g_assert (!((gsize)vt & 7));
1919 vt->rank = klass->rank;
1920 vt->domain = domain;
1922 mono_class_compute_gc_descriptor (klass);
1925 * We can't use typed allocation in the non-root domains, since the
1926 * collector needs the GC descriptor stored in the vtable even after
1927 * the mempool containing the vtable is destroyed when the domain is
1928 * unloaded. An alternative might be to allocate vtables in the GC
1929 * heap, but this does not seem to work (it leads to crashes inside
1930 * libgc). If that approach is tried, two gc descriptors need to be
1931 * allocated for each class: one for the root domain, and one for all
1932 * other domains. The second descriptor should contain a bit for the
1933 * vtable field in MonoObject, since we can no longer assume the
1934 * vtable is reachable by other roots after the appdomain is unloaded.
1936 if (!mono_gc_is_moving () && domain != mono_get_root_domain () && !mono_dont_free_domains)
1937 vt->gc_descr = MONO_GC_DESCRIPTOR_NULL;
1939 vt->gc_descr = klass->gc_descr;
1941 gc_bits = mono_gc_get_vtable_bits (klass);
1942 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
1944 vt->gc_bits = gc_bits;
1947 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
1948 if (klass->has_static_refs) {
1949 MonoGCDescriptor statics_gc_descr;
1951 gsize default_bitmap [4] = {0};
1954 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1955 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], klass->name_space, klass->name, class_size);*/
1956 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1957 vt->vtable [klass->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr, MONO_ROOT_SOURCE_STATIC, "managed static variables");
1958 if (bitmap != default_bitmap)
1961 vt->vtable [klass->vtable_size] = mono_domain_alloc0 (domain, class_size);
1963 vt->has_static_fields = TRUE;
1964 mono_stats.class_static_data_size += class_size;
1968 while ((field = mono_class_get_fields (klass, &iter))) {
1969 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1971 if (mono_field_is_deleted (field))
1973 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1974 gint32 special_static = klass->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (klass, field);
1975 if (special_static != SPECIAL_STATIC_NONE) {
1976 guint32 size, offset;
1978 gsize default_bitmap [4] = {0};
1983 if (mono_type_is_reference (field->type)) {
1984 default_bitmap [0] = 1;
1986 bitmap = default_bitmap;
1987 } else if (mono_type_is_struct (field->type)) {
1988 fclass = mono_class_from_mono_type (field->type);
1989 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
1990 numbits = max_set + 1;
1992 default_bitmap [0] = 0;
1994 bitmap = default_bitmap;
1996 size = mono_type_size (field->type, &align);
1997 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
1998 if (!domain->special_static_fields)
1999 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2000 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2001 if (bitmap != default_bitmap)
2004 * This marks the field as special static to speed up the
2005 * checks in mono_field_static_get/set_value ().
2011 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2012 MonoClass *fklass = mono_class_from_mono_type (field->type);
2013 const char *data = mono_field_get_data (field);
2015 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2016 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2017 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2020 if (fklass->valuetype) {
2021 memcpy (t, data, mono_class_value_size (fklass, NULL));
2023 /* it's a pointer type: add check */
2024 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2031 vt->max_interface_id = klass->max_interface_id;
2032 vt->interface_bitmap = klass->interface_bitmap;
2034 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2035 // class->name, klass->interface_offsets_count);
2037 /* Initialize vtable */
2038 if (callbacks.get_vtable_trampoline) {
2039 // This also covers the AOT case
2040 for (i = 0; i < klass->vtable_size; ++i) {
2041 vt->vtable [i] = callbacks.get_vtable_trampoline (vt, i);
2044 mono_class_setup_vtable (klass);
2046 for (i = 0; i < klass->vtable_size; ++i) {
2049 cm = klass->vtable [i];
2051 vt->vtable [i] = callbacks.create_jit_trampoline (domain, cm, error);
2052 if (!is_ok (error)) {
2053 mono_domain_unlock (domain);
2054 mono_loader_unlock ();
2061 if (imt_table_bytes) {
2062 /* Now that the vtable is full, we can actually fill up the IMT */
2063 for (i = 0; i < MONO_IMT_SIZE; ++i)
2064 interface_offsets [i] = callbacks.get_imt_trampoline (vt, i);
2068 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2069 * re-acquire them and check if another thread has created the vtable in the meantime.
2071 /* Special case System.MonoType to avoid infinite recursion */
2072 if (klass != mono_defaults.runtimetype_class) {
2073 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2074 if (!is_ok (error)) {
2075 mono_domain_unlock (domain);
2076 mono_loader_unlock ();
2080 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2081 /* This is unregistered in
2082 unregister_vtable_reflection_type() in
2084 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2087 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (klass));
2089 /* class_vtable_array keeps an array of created vtables
2091 g_ptr_array_add (domain->class_vtable_array, vt);
2092 /* klass->runtime_info is protected by the loader lock, both when
2093 * it it enlarged and when it is stored info.
2097 * Store the vtable in klass->runtime_info.
2098 * klass->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2100 mono_memory_barrier ();
2102 old_info = klass->runtime_info;
2103 if (old_info && old_info->max_domain >= domain->domain_id) {
2104 /* someone already created a large enough runtime info */
2105 old_info->domain_vtables [domain->domain_id] = vt;
2107 int new_size = domain->domain_id;
2109 new_size = MAX (new_size, old_info->max_domain);
2111 /* make the new size a power of two */
2113 while (new_size > i)
2116 /* this is a bounded memory retention issue: may want to
2117 * handle it differently when we'll have a rcu-like system.
2119 runtime_info = (MonoClassRuntimeInfo *)mono_image_alloc0 (klass->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2120 runtime_info->max_domain = new_size - 1;
2121 /* copy the stuff from the older info */
2123 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2125 runtime_info->domain_vtables [domain->domain_id] = vt;
2127 mono_memory_barrier ();
2128 klass->runtime_info = runtime_info;
2131 if (klass == mono_defaults.runtimetype_class) {
2132 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2133 if (!is_ok (error)) {
2134 mono_domain_unlock (domain);
2135 mono_loader_unlock ();
2139 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2140 /* This is unregistered in
2141 unregister_vtable_reflection_type() in
2143 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2146 mono_domain_unlock (domain);
2147 mono_loader_unlock ();
2149 /* make sure the parent is initialized */
2150 /*FIXME shouldn't this fail the current type?*/
2152 mono_class_vtable_full (domain, klass->parent, error);
2157 #ifndef DISABLE_REMOTING
2159 * mono_remote_class_is_interface_proxy:
2160 * \param remote_class
2162 * Returns TRUE if the given remote class is a proxying an interface (as
2163 * opposed to a class deriving from MarshalByRefObject).
2166 mono_remote_class_is_interface_proxy (MonoRemoteClass *remote_class)
2168 /* This if condition is taking advantage of how mono_remote_class ()
2169 * works: if that code changes, this needs to change too. */
2170 return (remote_class->interface_count >= 1 &&
2171 remote_class->proxy_class == mono_defaults.marshalbyrefobject_class);
2175 * mono_class_proxy_vtable:
2176 * \param domain the application domain
2177 * \param remove_class the remote class
2178 * \param error set on error
2179 * Creates a vtable for transparent proxies. It is basically
2180 * a copy of the real vtable of the class wrapped in \p remote_class,
2181 * but all function pointers invoke the remoting functions, and
2182 * \c vtable->klass points to the transparent proxy class, and not to \p class.
2184 * On failure returns NULL and sets \p error
2187 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type, MonoError *error)
2189 MONO_REQ_GC_UNSAFE_MODE;
2191 MonoVTable *vt, *pvt;
2192 int i, j, vtsize, extra_interface_vtsize = 0;
2193 guint32 max_interface_id;
2195 GSList *extra_interfaces = NULL;
2196 MonoClass *klass = remote_class->proxy_class;
2197 gpointer *interface_offsets;
2198 uint8_t *bitmap = NULL;
2200 size_t imt_table_bytes;
2202 #ifdef COMPRESSED_INTERFACE_BITMAP
2208 vt = mono_class_vtable (domain, klass);
2209 g_assert (vt); /*FIXME property handle failure*/
2210 max_interface_id = vt->max_interface_id;
2212 /* Calculate vtable space for extra interfaces */
2213 for (j = 0; j < remote_class->interface_count; j++) {
2214 MonoClass* iclass = remote_class->interfaces[j];
2218 /*FIXME test for interfaces with variant generic arguments*/
2219 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, iclass->interface_id))
2220 continue; /* interface implemented by the class */
2221 if (g_slist_find (extra_interfaces, iclass))
2224 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2226 method_count = mono_class_num_methods (iclass);
2228 ifaces = mono_class_get_implemented_interfaces (iclass, error);
2232 for (i = 0; i < ifaces->len; ++i) {
2233 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2234 /*FIXME test for interfaces with variant generic arguments*/
2235 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, ic->interface_id))
2236 continue; /* interface implemented by the class */
2237 if (g_slist_find (extra_interfaces, ic))
2239 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2240 method_count += mono_class_num_methods (ic);
2242 g_ptr_array_free (ifaces, TRUE);
2246 extra_interface_vtsize += method_count * sizeof (gpointer);
2247 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2250 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2251 mono_stats.imt_number_of_tables++;
2252 mono_stats.imt_tables_size += imt_table_bytes;
2254 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer);
2256 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2258 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2259 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2260 g_assert (!((gsize)pvt & 7));
2262 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer));
2264 pvt->klass = mono_defaults.transparent_proxy_class;
2265 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2266 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2268 if (mono_remote_class_is_interface_proxy (remote_class)) {
2269 /* If it's a transparent proxy for an interface, set the
2270 * MonoVTable:type to the interface type, not the placeholder
2271 * MarshalByRefObject class. This is used when mini JITs calls
2272 * to Object.GetType ()
2274 MonoType *itf_proxy_type = &remote_class->interfaces[0]->byval_arg;
2275 pvt->type = mono_type_get_object_checked (domain, itf_proxy_type, error);
2280 /* initialize vtable */
2281 mono_class_setup_vtable (klass);
2282 for (i = 0; i < klass->vtable_size; ++i) {
2285 if ((cm = klass->vtable [i])) {
2286 pvt->vtable [i] = create_remoting_trampoline (domain, cm, target_type, error);
2290 pvt->vtable [i] = NULL;
2293 if (mono_class_is_abstract (klass)) {
2294 /* create trampolines for abstract methods */
2295 for (k = klass; k; k = k->parent) {
2297 gpointer iter = NULL;
2298 while ((m = mono_class_get_methods (k, &iter)))
2299 if (!pvt->vtable [m->slot]) {
2300 pvt->vtable [m->slot] = create_remoting_trampoline (domain, m, target_type, error);
2307 pvt->max_interface_id = max_interface_id;
2308 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2309 #ifdef COMPRESSED_INTERFACE_BITMAP
2310 bitmap = (uint8_t *)g_malloc0 (bsize);
2312 bitmap = (uint8_t *)mono_domain_alloc0 (domain, bsize);
2315 for (i = 0; i < klass->interface_offsets_count; ++i) {
2316 int interface_id = klass->interfaces_packed [i]->interface_id;
2317 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2320 if (extra_interfaces) {
2321 int slot = klass->vtable_size;
2327 /* Create trampolines for the methods of the interfaces */
2328 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2329 interf = (MonoClass *)list_item->data;
2331 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2335 while ((cm = mono_class_get_methods (interf, &iter))) {
2336 pvt->vtable [slot + j++] = create_remoting_trampoline (domain, cm, target_type, error);
2341 slot += mono_class_num_methods (interf);
2345 /* Now that the vtable is full, we can actually fill up the IMT */
2346 build_imt (klass, pvt, domain, interface_offsets, extra_interfaces);
2347 if (extra_interfaces) {
2348 g_slist_free (extra_interfaces);
2351 #ifdef COMPRESSED_INTERFACE_BITMAP
2352 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2353 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2354 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2357 pvt->interface_bitmap = bitmap;
2361 if (extra_interfaces)
2362 g_slist_free (extra_interfaces);
2363 #ifdef COMPRESSED_INTERFACE_BITMAP
2369 #endif /* DISABLE_REMOTING */
2372 * mono_class_field_is_special_static:
2373 * \returns whether \p field is a thread/context static field.
2376 mono_class_field_is_special_static (MonoClassField *field)
2378 MONO_REQ_GC_NEUTRAL_MODE
2380 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2382 if (mono_field_is_deleted (field))
2384 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2385 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2392 * mono_class_field_get_special_static_type:
2393 * \param field The \c MonoClassField describing the field.
2394 * \returns \c SPECIAL_STATIC_THREAD if the field is thread static, \c SPECIAL_STATIC_CONTEXT if it is context static,
2395 * \c SPECIAL_STATIC_NONE otherwise.
2398 mono_class_field_get_special_static_type (MonoClassField *field)
2400 MONO_REQ_GC_NEUTRAL_MODE
2402 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2403 return SPECIAL_STATIC_NONE;
2404 if (mono_field_is_deleted (field))
2405 return SPECIAL_STATIC_NONE;
2406 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2407 return field_is_special_static (field->parent, field);
2408 return SPECIAL_STATIC_NONE;
2412 * mono_class_has_special_static_fields:
2413 * \returns whether \p klass has any thread/context static fields.
2416 mono_class_has_special_static_fields (MonoClass *klass)
2418 MONO_REQ_GC_NEUTRAL_MODE
2420 MonoClassField *field;
2424 while ((field = mono_class_get_fields (klass, &iter))) {
2425 g_assert (field->parent == klass);
2426 if (mono_class_field_is_special_static (field))
2433 #ifndef DISABLE_REMOTING
2435 * create_remote_class_key:
2436 * Creates an array of pointers that can be used as a hash key for a remote class.
2437 * The first element of the array is the number of pointers.
2440 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2442 MONO_REQ_GC_NEUTRAL_MODE;
2447 if (remote_class == NULL) {
2448 if (mono_class_is_interface (extra_class)) {
2449 key = (void **)g_malloc (sizeof(gpointer) * 3);
2450 key [0] = GINT_TO_POINTER (2);
2451 key [1] = mono_defaults.marshalbyrefobject_class;
2452 key [2] = extra_class;
2454 key = (void **)g_malloc (sizeof(gpointer) * 2);
2455 key [0] = GINT_TO_POINTER (1);
2456 key [1] = extra_class;
2459 if (extra_class != NULL && mono_class_is_interface (extra_class)) {
2460 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2461 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2462 key [1] = remote_class->proxy_class;
2464 // Keep the list of interfaces sorted
2465 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2466 if (extra_class && remote_class->interfaces [i] > extra_class) {
2467 key [j++] = extra_class;
2470 key [j] = remote_class->interfaces [i];
2473 key [j] = extra_class;
2475 // Replace the old class. The interface list is the same
2476 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2477 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2478 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2479 for (i = 0; i < remote_class->interface_count; i++)
2480 key [2 + i] = remote_class->interfaces [i];
2488 * copy_remote_class_key:
2490 * Make a copy of KEY in the domain and return the copy.
2493 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2495 MONO_REQ_GC_NEUTRAL_MODE
2497 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2498 gpointer *mp_key = (gpointer *)mono_domain_alloc (domain, key_size);
2500 memcpy (mp_key, key, key_size);
2506 * mono_remote_class:
2507 * \param domain the application domain
2508 * \param class_name name of the remote class
2509 * \param error set on error
2510 * Creates and initializes a \c MonoRemoteClass object for a remote type.
2511 * On failure returns NULL and sets \p error
2514 mono_remote_class (MonoDomain *domain, MonoStringHandle class_name, MonoClass *proxy_class, MonoError *error)
2516 MONO_REQ_GC_UNSAFE_MODE;
2518 MonoRemoteClass *rc;
2519 gpointer* key, *mp_key;
2524 key = create_remote_class_key (NULL, proxy_class);
2526 mono_domain_lock (domain);
2527 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2531 mono_domain_unlock (domain);
2535 name = mono_string_to_utf8_mp (domain->mp, MONO_HANDLE_RAW (class_name), error);
2536 if (!is_ok (error)) {
2538 mono_domain_unlock (domain);
2542 mp_key = copy_remote_class_key (domain, key);
2546 if (mono_class_is_interface (proxy_class)) {
2547 /* If we need to proxy an interface, we use this stylized
2548 * representation (interface_count >= 1, proxy_class is
2549 * MarshalByRefObject). The code in
2550 * mono_remote_class_is_interface_proxy () depends on being
2551 * able to detect that we're doing this, so if this
2552 * representation changes, change GetType, too. */
2553 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2554 rc->interface_count = 1;
2555 rc->interfaces [0] = proxy_class;
2556 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2558 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2559 rc->interface_count = 0;
2560 rc->proxy_class = proxy_class;
2563 rc->default_vtable = NULL;
2564 rc->xdomain_vtable = NULL;
2565 rc->proxy_class_name = name;
2566 #ifndef DISABLE_PERFCOUNTERS
2567 mono_perfcounters->loader_bytes += mono_string_length (MONO_HANDLE_RAW (class_name)) + 1;
2570 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2572 mono_domain_unlock (domain);
2577 * clone_remote_class:
2578 * Creates a copy of the remote_class, adding the provided class or interface
2580 static MonoRemoteClass*
2581 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2583 MONO_REQ_GC_NEUTRAL_MODE;
2585 MonoRemoteClass *rc;
2586 gpointer* key, *mp_key;
2588 key = create_remote_class_key (remote_class, extra_class);
2589 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2595 mp_key = copy_remote_class_key (domain, key);
2599 if (mono_class_is_interface (extra_class)) {
2601 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2602 rc->proxy_class = remote_class->proxy_class;
2603 rc->interface_count = remote_class->interface_count + 1;
2605 // Keep the list of interfaces sorted, since the hash key of
2606 // the remote class depends on this
2607 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2608 if (remote_class->interfaces [i] > extra_class && i == j)
2609 rc->interfaces [j++] = extra_class;
2610 rc->interfaces [j] = remote_class->interfaces [i];
2613 rc->interfaces [j] = extra_class;
2615 // Replace the old class. The interface array is the same
2616 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2617 rc->proxy_class = extra_class;
2618 rc->interface_count = remote_class->interface_count;
2619 if (rc->interface_count > 0)
2620 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2623 rc->default_vtable = NULL;
2624 rc->xdomain_vtable = NULL;
2625 rc->proxy_class_name = remote_class->proxy_class_name;
2627 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2633 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxyHandle rp, MonoError *error)
2635 MONO_REQ_GC_UNSAFE_MODE;
2639 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2640 mono_domain_lock (domain);
2641 gint32 target_domain_id = MONO_HANDLE_GETVAL (rp, target_domain_id);
2642 if (target_domain_id != -1) {
2643 if (remote_class->xdomain_vtable == NULL)
2644 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN, error);
2645 mono_domain_unlock (domain);
2646 mono_loader_unlock ();
2647 return_val_if_nok (error, NULL);
2648 return remote_class->xdomain_vtable;
2650 if (remote_class->default_vtable == NULL) {
2651 MonoReflectionTypeHandle reftype = MONO_HANDLE_NEW (MonoReflectionType, NULL);
2652 MONO_HANDLE_GET (reftype, rp, class_to_proxy);
2654 MonoType *type = MONO_HANDLE_GETVAL (reftype, type);
2655 MonoClass *klass = mono_class_from_mono_type (type);
2657 if ((mono_class_is_com_object (klass) || (mono_class_get_com_object_class () && klass == mono_class_get_com_object_class ())) && !mono_vtable_is_remote (mono_class_vtable (mono_domain_get (), klass)))
2658 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP, error);
2661 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN, error);
2662 /* N.B. both branches of the if modify error */
2663 if (!is_ok (error)) {
2664 mono_domain_unlock (domain);
2665 mono_loader_unlock ();
2670 mono_domain_unlock (domain);
2671 mono_loader_unlock ();
2672 return remote_class->default_vtable;
2676 * mono_upgrade_remote_class:
2677 * \param domain the application domain
2678 * \param tproxy the proxy whose remote class has to be upgraded.
2679 * \param klass class to which the remote class can be casted.
2680 * \param error set on error
2681 * Updates the vtable of the remote class by adding the necessary method slots
2682 * and interface offsets so it can be safely casted to klass. klass can be a
2683 * class or an interface. On success returns TRUE, on failure returns FALSE and sets \p error.
2686 mono_upgrade_remote_class (MonoDomain *domain, MonoObjectHandle proxy_object, MonoClass *klass, MonoError *error)
2688 MONO_REQ_GC_UNSAFE_MODE;
2692 MonoTransparentProxyHandle tproxy = MONO_HANDLE_CAST (MonoTransparentProxy, proxy_object);
2693 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (tproxy, remote_class);
2695 gboolean redo_vtable;
2696 if (mono_class_is_interface (klass)) {
2699 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2700 if (remote_class->interfaces [i] == klass)
2701 redo_vtable = FALSE;
2704 redo_vtable = (remote_class->proxy_class != klass);
2707 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2708 mono_domain_lock (domain);
2710 MonoRemoteClass *fresh_remote_class = clone_remote_class (domain, remote_class, klass);
2711 MONO_HANDLE_SETVAL (tproxy, remote_class, MonoRemoteClass*, fresh_remote_class);
2712 MonoRealProxyHandle real_proxy = MONO_HANDLE_NEW (MonoRealProxy, NULL);
2713 MONO_HANDLE_GET (real_proxy, tproxy, rp);
2714 MONO_HANDLE_SETVAL (proxy_object, vtable, MonoVTable*, mono_remote_class_vtable (domain, fresh_remote_class, real_proxy, error));
2720 mono_domain_unlock (domain);
2721 mono_loader_unlock ();
2722 return is_ok (error);
2724 #endif /* DISABLE_REMOTING */
2728 * mono_object_get_virtual_method:
2729 * \param obj object to operate on.
2730 * \param method method
2731 * Retrieves the \c MonoMethod that would be called on \p obj if \p obj is passed as
2732 * the instance of a callvirt of \p method.
2735 mono_object_get_virtual_method (MonoObject *obj_raw, MonoMethod *method)
2737 MONO_REQ_GC_UNSAFE_MODE;
2738 HANDLE_FUNCTION_ENTER ();
2740 MONO_HANDLE_DCL (MonoObject, obj);
2741 MonoMethod *result = mono_object_handle_get_virtual_method (obj, method, &error);
2742 mono_error_assert_ok (&error);
2743 HANDLE_FUNCTION_RETURN_VAL (result);
2747 * mono_object_handle_get_virtual_method:
2748 * \param obj object to operate on.
2749 * \param method method
2750 * Retrieves the \c MonoMethod that would be called on \p obj if \p obj is passed as
2751 * the instance of a callvirt of \p method.
2754 mono_object_handle_get_virtual_method (MonoObjectHandle obj, MonoMethod *method, MonoError *error)
2758 gboolean is_proxy = FALSE;
2759 MonoClass *klass = mono_handle_class (obj);
2760 if (mono_class_is_transparent_proxy (klass)) {
2761 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), remote_class);
2762 klass = remote_class->proxy_class;
2765 return class_get_virtual_method (klass, method, is_proxy, error);
2769 class_get_virtual_method (MonoClass *klass, MonoMethod *method, gboolean is_proxy, MonoError *error)
2774 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2777 mono_class_setup_vtable (klass);
2778 MonoMethod **vtable = klass->vtable;
2780 if (method->slot == -1) {
2781 /* method->slot might not be set for instances of generic methods */
2782 if (method->is_inflated) {
2783 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2784 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2787 g_assert_not_reached ();
2791 MonoMethod *res = NULL;
2792 /* check method->slot is a valid index: perform isinstance? */
2793 if (method->slot != -1) {
2794 if (mono_class_is_interface (method->klass)) {
2796 gboolean variance_used = FALSE;
2797 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2798 g_assert (iface_offset > 0);
2799 res = vtable [iface_offset + method->slot];
2802 res = vtable [method->slot];
2806 #ifndef DISABLE_REMOTING
2808 /* It may be an interface, abstract class method or generic method */
2809 if (!res || mono_method_signature (res)->generic_param_count)
2812 /* generic methods demand invoke_with_check */
2813 if (mono_method_signature (res)->generic_param_count)
2814 res = mono_marshal_get_remoting_invoke_with_check (res);
2817 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2818 res = mono_cominterop_get_invoke (res);
2821 res = mono_marshal_get_remoting_invoke (res);
2826 if (method->is_inflated) {
2827 /* Have to inflate the result */
2828 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, error);
2836 do_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2838 MONO_REQ_GC_UNSAFE_MODE;
2840 MonoObject *result = NULL;
2842 g_assert (callbacks.runtime_invoke);
2846 MONO_PROFILER_RAISE (method_begin_invoke, (method));
2848 result = callbacks.runtime_invoke (method, obj, params, exc, error);
2850 MONO_PROFILER_RAISE (method_end_invoke, (method));
2852 if (!mono_error_ok (error))
2859 * mono_runtime_invoke:
2860 * \param method method to invoke
2861 * \param obj object instance
2862 * \param params arguments to the method
2863 * \param exc exception information.
2864 * Invokes the method represented by \p method on the object \p obj.
2865 * \p obj is the \c this pointer, it should be NULL for static
2866 * methods, a \c MonoObject* for object instances and a pointer to
2867 * the value type for value types.
2869 * The params array contains the arguments to the method with the
2870 * same convention: \c MonoObject* pointers for object instances and
2871 * pointers to the value type otherwise.
2873 * From unmanaged code you'll usually use the
2874 * \c mono_runtime_invoke variant.
2876 * Note that this function doesn't handle virtual methods for
2877 * you, it will exec the exact method you pass: we still need to
2878 * expose a function to lookup the derived class implementation
2879 * of a virtual method (there are examples of this in the code,
2882 * You can pass NULL as the \p exc argument if you don't want to
2883 * catch exceptions, otherwise, \c *exc will be set to the exception
2884 * thrown, if any. if an exception is thrown, you can't use the
2885 * \c MonoObject* result from the function.
2887 * If the method returns a value type, it is boxed in an object
2891 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2896 res = mono_runtime_try_invoke (method, obj, params, exc, &error);
2897 if (*exc == NULL && !mono_error_ok(&error)) {
2898 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
2900 mono_error_cleanup (&error);
2902 res = mono_runtime_invoke_checked (method, obj, params, &error);
2903 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
2909 * mono_runtime_try_invoke:
2910 * \param method method to invoke
2911 * \param obj object instance
2912 * \param params arguments to the method
2913 * \param exc exception information.
2914 * \param error set on error
2915 * Invokes the method represented by \p method on the object \p obj.
2917 * \p obj is the \c this pointer, it should be NULL for static
2918 * methods, a \c MonoObject* for object instances and a pointer to
2919 * the value type for value types.
2921 * The params array contains the arguments to the method with the
2922 * same convention: \c MonoObject* pointers for object instances and
2923 * pointers to the value type otherwise.
2925 * From unmanaged code you'll usually use the
2926 * mono_runtime_invoke() variant.
2928 * Note that this function doesn't handle virtual methods for
2929 * you, it will exec the exact method you pass: we still need to
2930 * expose a function to lookup the derived class implementation
2931 * of a virtual method (there are examples of this in the code,
2934 * For this function, you must not pass NULL as the \p exc argument if
2935 * you don't want to catch exceptions, use
2936 * mono_runtime_invoke_checked(). If an exception is thrown, you
2937 * can't use the \c MonoObject* result from the function.
2939 * If this method cannot be invoked, \p error will be set and \p exc and
2940 * the return value must not be used.
2942 * If the method returns a value type, it is boxed in an object
2946 mono_runtime_try_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError* error)
2948 MONO_REQ_GC_UNSAFE_MODE;
2950 g_assert (exc != NULL);
2952 if (mono_runtime_get_no_exec ())
2953 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2955 return do_runtime_invoke (method, obj, params, exc, error);
2959 * mono_runtime_invoke_checked:
2960 * \param method method to invoke
2961 * \param obj object instance
2962 * \param params arguments to the method
2963 * \param error set on error
2964 * Invokes the method represented by \p method on the object \p obj.
2966 * \p obj is the \c this pointer, it should be NULL for static
2967 * methods, a \c MonoObject* for object instances and a pointer to
2968 * the value type for value types.
2970 * The \p params array contains the arguments to the method with the
2971 * same convention: \c MonoObject* pointers for object instances and
2972 * pointers to the value type otherwise.
2974 * From unmanaged code you'll usually use the
2975 * mono_runtime_invoke() variant.
2977 * Note that this function doesn't handle virtual methods for
2978 * you, it will exec the exact method you pass: we still need to
2979 * expose a function to lookup the derived class implementation
2980 * of a virtual method (there are examples of this in the code,
2983 * If an exception is thrown, you can't use the \c MonoObject* result
2984 * from the function.
2986 * If this method cannot be invoked, \p error will be set. If the
2987 * method throws an exception (and we're in coop mode) the exception
2988 * will be set in \p error.
2990 * If the method returns a value type, it is boxed in an object
2994 mono_runtime_invoke_checked (MonoMethod *method, void *obj, void **params, MonoError* error)
2996 MONO_REQ_GC_UNSAFE_MODE;
2998 if (mono_runtime_get_no_exec ())
2999 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
3001 return do_runtime_invoke (method, obj, params, NULL, error);
3005 * mono_method_get_unmanaged_thunk:
3006 * \param method method to generate a thunk for.
3008 * Returns an \c unmanaged->managed thunk that can be used to call
3009 * a managed method directly from C.
3011 * The thunk's C signature closely matches the managed signature:
3013 * C#: <code>public bool Equals (object obj);</code>
3015 * C: <code>typedef MonoBoolean (*Equals)(MonoObject*, MonoObject*, MonoException**);</code>
3017 * The 1st (<code>this</code>) parameter must not be used with static methods:
3019 * C#: <code>public static bool ReferenceEquals (object a, object b);</code>
3021 * C: <code>typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*, MonoException**);</code>
3023 * The last argument must be a non-null \c MonoException* pointer.
3024 * It has "out" semantics. After invoking the thunk, \c *ex will be NULL if no
3025 * exception has been thrown in managed code. Otherwise it will point
3026 * to the \c MonoException* caught by the thunk. In this case, the result of
3027 * the thunk is undefined:
3030 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
3032 * MonoException *ex = NULL;
3034 * Equals func = mono_method_get_unmanaged_thunk (method);
3036 * MonoBoolean res = func (thisObj, objToCompare, &ex);
3040 * // handle exception
3045 * The calling convention of the thunk matches the platform's default
3046 * convention. This means that under Windows, C declarations must
3047 * contain the \c __stdcall attribute:
3049 * C: <code>typedef MonoBoolean (__stdcall *Equals)(MonoObject*, MonoObject*, MonoException**);</code>
3053 * Value type arguments and return values are treated as they were objects:
3055 * C#: <code>public static Rectangle Intersect (Rectangle a, Rectangle b);</code>
3056 * C: <code>typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);</code>
3058 * Arguments must be properly boxed upon trunk's invocation, while return
3059 * values must be unboxed.
3062 mono_method_get_unmanaged_thunk (MonoMethod *method)
3064 MONO_REQ_GC_NEUTRAL_MODE;
3065 MONO_REQ_API_ENTRYPOINT;
3070 g_assert (!mono_threads_is_coop_enabled ());
3072 MONO_ENTER_GC_UNSAFE;
3073 method = mono_marshal_get_thunk_invoke_wrapper (method);
3074 res = mono_compile_method_checked (method, &error);
3075 mono_error_cleanup (&error);
3076 MONO_EXIT_GC_UNSAFE;
3082 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
3084 MONO_REQ_GC_UNSAFE_MODE;
3088 /* object fields cannot be byref, so we don't need a
3090 gpointer *p = (gpointer*)dest;
3097 case MONO_TYPE_BOOLEAN:
3099 case MONO_TYPE_U1: {
3100 guint8 *p = (guint8*)dest;
3101 *p = value ? *(guint8*)value : 0;
3106 case MONO_TYPE_CHAR: {
3107 guint16 *p = (guint16*)dest;
3108 *p = value ? *(guint16*)value : 0;
3111 #if SIZEOF_VOID_P == 4
3116 case MONO_TYPE_U4: {
3117 gint32 *p = (gint32*)dest;
3118 *p = value ? *(gint32*)value : 0;
3121 #if SIZEOF_VOID_P == 8
3126 case MONO_TYPE_U8: {
3127 gint64 *p = (gint64*)dest;
3128 *p = value ? *(gint64*)value : 0;
3131 case MONO_TYPE_R4: {
3132 float *p = (float*)dest;
3133 *p = value ? *(float*)value : 0;
3136 case MONO_TYPE_R8: {
3137 double *p = (double*)dest;
3138 *p = value ? *(double*)value : 0;
3141 case MONO_TYPE_STRING:
3142 case MONO_TYPE_SZARRAY:
3143 case MONO_TYPE_CLASS:
3144 case MONO_TYPE_OBJECT:
3145 case MONO_TYPE_ARRAY:
3146 mono_gc_wbarrier_generic_store (dest, deref_pointer ? *(MonoObject **)value : (MonoObject *)value);
3148 case MONO_TYPE_FNPTR:
3149 case MONO_TYPE_PTR: {
3150 gpointer *p = (gpointer*)dest;
3151 *p = deref_pointer? *(gpointer*)value: value;
3154 case MONO_TYPE_VALUETYPE:
3155 /* note that 't' and 'type->type' can be different */
3156 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3157 t = mono_class_enum_basetype (type->data.klass)->type;
3160 MonoClass *klass = mono_class_from_mono_type (type);
3161 int size = mono_class_value_size (klass, NULL);
3163 mono_gc_bzero_atomic (dest, size);
3165 mono_gc_wbarrier_value_copy (dest, value, 1, klass);
3168 case MONO_TYPE_GENERICINST:
3169 t = type->data.generic_class->container_class->byval_arg.type;
3172 g_error ("got type %x", type->type);
3177 * mono_field_set_value:
3178 * \param obj Instance object
3179 * \param field \c MonoClassField describing the field to set
3180 * \param value The value to be set
3182 * Sets the value of the field described by \p field in the object instance \p obj
3183 * to the value passed in \p value. This method should only be used for instance
3184 * fields. For static fields, use \c mono_field_static_set_value.
3186 * The value must be in the native format of the field type.
3189 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3191 MONO_REQ_GC_UNSAFE_MODE;
3195 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3197 dest = (char*)obj + field->offset;
3198 mono_copy_value (field->type, dest, value, FALSE);
3202 * mono_field_static_set_value:
3203 * \param field \c MonoClassField describing the field to set
3204 * \param value The value to be set
3205 * Sets the value of the static field described by \p field
3206 * to the value passed in \p value.
3207 * The value must be in the native format of the field type.
3210 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3212 MONO_REQ_GC_UNSAFE_MODE;
3216 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3217 /* you cant set a constant! */
3218 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3220 if (field->offset == -1) {
3221 /* Special static */
3224 mono_domain_lock (vt->domain);
3225 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3226 mono_domain_unlock (vt->domain);
3227 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3229 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3231 mono_copy_value (field->type, dest, value, FALSE);
3235 * mono_vtable_get_static_field_data:
3237 * Internal use function: return a pointer to the memory holding the static fields
3238 * for a class or NULL if there are no static fields.
3239 * This is exported only for use by the debugger.
3242 mono_vtable_get_static_field_data (MonoVTable *vt)
3244 MONO_REQ_GC_NEUTRAL_MODE
3246 if (!vt->has_static_fields)
3248 return vt->vtable [vt->klass->vtable_size];
3252 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3254 MONO_REQ_GC_UNSAFE_MODE;
3258 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3259 if (field->offset == -1) {
3260 /* Special static */
3263 mono_domain_lock (vt->domain);
3264 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3265 mono_domain_unlock (vt->domain);
3266 src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3268 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3271 src = (guint8*)obj + field->offset;
3278 * mono_field_get_value:
3279 * \param obj Object instance
3280 * \param field \c MonoClassField describing the field to fetch information from
3281 * \param value pointer to the location where the value will be stored
3282 * Use this routine to get the value of the field \p field in the object
3285 * The pointer provided by value must be of the field type, for reference
3286 * types this is a \c MonoObject*, for value types its the actual pointer to
3294 * mono_field_get_value (obj, int_field, &i);
3298 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3300 MONO_REQ_GC_UNSAFE_MODE;
3306 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3308 src = (char*)obj + field->offset;
3309 mono_copy_value (field->type, value, src, TRUE);
3313 * mono_field_get_value_object:
3314 * \param domain domain where the object will be created (if boxing)
3315 * \param field \c MonoClassField describing the field to fetch information from
3316 * \param obj The object instance for the field.
3317 * \returns a new \c MonoObject with the value from the given field. If the
3318 * field represents a value type, the value is boxed.
3321 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3324 MonoObject* result = mono_field_get_value_object_checked (domain, field, obj, &error);
3325 mono_error_assert_ok (&error);
3330 * mono_field_get_value_object_checked:
3331 * \param domain domain where the object will be created (if boxing)
3332 * \param field \c MonoClassField describing the field to fetch information from
3333 * \param obj The object instance for the field.
3334 * \param error Set on error.
3335 * \returns a new \c MonoObject with the value from the given field. If the
3336 * field represents a value type, the value is boxed. On error returns NULL and sets \p error.
3339 mono_field_get_value_object_checked (MonoDomain *domain, MonoClassField *field, MonoObject *obj, MonoError *error)
3341 MONO_REQ_GC_UNSAFE_MODE;
3347 MonoVTable *vtable = NULL;
3349 gboolean is_static = FALSE;
3350 gboolean is_ref = FALSE;
3351 gboolean is_literal = FALSE;
3352 gboolean is_ptr = FALSE;
3353 MonoType *type = mono_field_get_type_checked (field, error);
3355 return_val_if_nok (error, NULL);
3357 switch (type->type) {
3358 case MONO_TYPE_STRING:
3359 case MONO_TYPE_OBJECT:
3360 case MONO_TYPE_CLASS:
3361 case MONO_TYPE_ARRAY:
3362 case MONO_TYPE_SZARRAY:
3367 case MONO_TYPE_BOOLEAN:
3370 case MONO_TYPE_CHAR:
3379 case MONO_TYPE_VALUETYPE:
3380 is_ref = type->byref;
3382 case MONO_TYPE_GENERICINST:
3383 is_ref = !mono_type_generic_inst_is_valuetype (type);
3389 g_error ("type 0x%x not handled in "
3390 "mono_field_get_value_object", type->type);
3394 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3397 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3401 vtable = mono_class_vtable_full (domain, field->parent, error);
3402 return_val_if_nok (error, NULL);
3404 if (!vtable->initialized) {
3405 mono_runtime_class_init_full (vtable, error);
3406 return_val_if_nok (error, NULL);
3415 get_default_field_value (domain, field, &o, error);
3416 return_val_if_nok (error, NULL);
3417 } else if (is_static) {
3418 mono_field_static_get_value_checked (vtable, field, &o, error);
3419 return_val_if_nok (error, NULL);
3421 mono_field_get_value (obj, field, &o);
3427 static MonoMethod *m;
3433 MonoClass *ptr_klass = mono_class_get_pointer_class ();
3434 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3440 get_default_field_value (domain, field, v, error);
3441 return_val_if_nok (error, NULL);
3442 } else if (is_static) {
3443 mono_field_static_get_value_checked (vtable, field, v, error);
3444 return_val_if_nok (error, NULL);
3446 mono_field_get_value (obj, field, v);
3449 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3450 args [0] = ptr ? *ptr : NULL;
3451 args [1] = mono_type_get_object_checked (mono_domain_get (), type, error);
3452 return_val_if_nok (error, NULL);
3454 o = mono_runtime_invoke_checked (m, NULL, args, error);
3455 return_val_if_nok (error, NULL);
3460 /* boxed value type */
3461 klass = mono_class_from_mono_type (type);
3463 if (mono_class_is_nullable (klass))
3464 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass, error);
3466 o = mono_object_new_checked (domain, klass, error);
3467 return_val_if_nok (error, NULL);
3468 v = ((gchar *) o) + sizeof (MonoObject);
3471 get_default_field_value (domain, field, v, error);
3472 return_val_if_nok (error, NULL);
3473 } else if (is_static) {
3474 mono_field_static_get_value_checked (vtable, field, v, error);
3475 return_val_if_nok (error, NULL);
3477 mono_field_get_value (obj, field, v);
3484 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value, MonoError *error)
3486 MONO_REQ_GC_UNSAFE_MODE;
3490 const char *p = blob;
3491 mono_metadata_decode_blob_size (p, &p);
3494 case MONO_TYPE_BOOLEAN:
3497 *(guint8 *) value = *p;
3499 case MONO_TYPE_CHAR:
3502 *(guint16*) value = read16 (p);
3506 *(guint32*) value = read32 (p);
3510 *(guint64*) value = read64 (p);
3513 readr4 (p, (float*) value);
3516 readr8 (p, (double*) value);
3518 case MONO_TYPE_STRING:
3519 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob, error);
3521 case MONO_TYPE_CLASS:
3522 *(gpointer*) value = NULL;
3526 g_warning ("type 0x%02x should not be in constant table", type);
3532 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error)
3534 MONO_REQ_GC_NEUTRAL_MODE;
3536 MonoTypeEnum def_type;
3541 data = mono_class_get_field_default_value (field, &def_type);
3542 mono_get_constant_value_from_blob (domain, def_type, data, value, error);
3546 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3548 MONO_REQ_GC_UNSAFE_MODE;
3554 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3556 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3557 get_default_field_value (vt->domain, field, value, error);
3561 if (field->offset == -1) {
3562 /* Special static */
3563 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3564 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3566 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3568 mono_copy_value (field->type, value, src, TRUE);
3572 * mono_field_static_get_value:
3573 * \param vt vtable to the object
3574 * \param field \c MonoClassField describing the field to fetch information from
3575 * \param value where the value is returned
3576 * Use this routine to get the value of the static field \p field value.
3578 * The pointer provided by value must be of the field type, for reference
3579 * types this is a \c MonoObject*, for value types its the actual pointer to
3587 * mono_field_static_get_value (vt, int_field, &i);
3591 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3593 MONO_REQ_GC_NEUTRAL_MODE;
3596 mono_field_static_get_value_checked (vt, field, value, &error);
3597 mono_error_cleanup (&error);
3601 * mono_field_static_get_value_checked:
3602 * \param vt vtable to the object
3603 * \param field \c MonoClassField describing the field to fetch information from
3604 * \param value where the value is returned
3605 * \param error set on error
3606 * Use this routine to get the value of the static field \p field value.
3608 * The pointer provided by value must be of the field type, for reference
3609 * types this is a \c MonoObject*, for value types its the actual pointer to
3614 * mono_field_static_get_value_checked (vt, int_field, &i, error);
3615 * if (!is_ok (error)) { ... }
3617 * On failure sets \p error.
3620 mono_field_static_get_value_checked (MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3622 MONO_REQ_GC_NEUTRAL_MODE;
3624 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value, error);
3628 * mono_property_set_value:
3629 * \param prop MonoProperty to set
3630 * \param obj instance object on which to act
3631 * \param params parameters to pass to the propery
3632 * \param exc optional exception
3633 * Invokes the property's set method with the given arguments on the
3634 * object instance obj (or NULL for static properties).
3636 * You can pass NULL as the exc argument if you don't want to
3637 * catch exceptions, otherwise, \c *exc will be set to the exception
3638 * thrown, if any. if an exception is thrown, you can't use the
3639 * \c MonoObject* result from the function.
3642 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3644 MONO_REQ_GC_UNSAFE_MODE;
3647 do_runtime_invoke (prop->set, obj, params, exc, &error);
3648 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3649 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3651 mono_error_cleanup (&error);
3656 * mono_property_set_value_checked:
3657 * \param prop \c MonoProperty to set
3658 * \param obj instance object on which to act
3659 * \param params parameters to pass to the propery
3660 * \param error set on error
3661 * Invokes the property's set method with the given arguments on the
3662 * object instance \p obj (or NULL for static properties).
3663 * \returns TRUE on success. On failure returns FALSE and sets \p error.
3664 * If an exception is thrown, it will be caught and returned via \p error.
3667 mono_property_set_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3669 MONO_REQ_GC_UNSAFE_MODE;
3674 do_runtime_invoke (prop->set, obj, params, &exc, error);
3675 if (exc != NULL && is_ok (error))
3676 mono_error_set_exception_instance (error, (MonoException*)exc);
3677 return is_ok (error);
3681 * mono_property_get_value:
3682 * \param prop \c MonoProperty to fetch
3683 * \param obj instance object on which to act
3684 * \param params parameters to pass to the propery
3685 * \param exc optional exception
3686 * Invokes the property's \c get method with the given arguments on the
3687 * object instance \p obj (or NULL for static properties).
3689 * You can pass NULL as the \p exc argument if you don't want to
3690 * catch exceptions, otherwise, \c *exc will be set to the exception
3691 * thrown, if any. if an exception is thrown, you can't use the
3692 * \c MonoObject* result from the function.
3694 * \returns the value from invoking the \c get method on the property.
3697 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3699 MONO_REQ_GC_UNSAFE_MODE;
3702 MonoObject *val = do_runtime_invoke (prop->get, obj, params, exc, &error);
3703 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3704 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3706 mono_error_cleanup (&error); /* FIXME don't raise here */
3713 * mono_property_get_value_checked:
3714 * \param prop \c MonoProperty to fetch
3715 * \param obj instance object on which to act
3716 * \param params parameters to pass to the propery
3717 * \param error set on error
3718 * Invokes the property's \c get method with the given arguments on the
3719 * object instance obj (or NULL for static properties).
3721 * If an exception is thrown, you can't use the
3722 * \c MonoObject* result from the function. The exception will be propagated via \p error.
3724 * \returns the value from invoking the get method on the property. On
3725 * failure returns NULL and sets \p error.
3728 mono_property_get_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3730 MONO_REQ_GC_UNSAFE_MODE;
3733 MonoObject *val = do_runtime_invoke (prop->get, obj, params, &exc, error);
3734 if (exc != NULL && !is_ok (error))
3735 mono_error_set_exception_instance (error, (MonoException*) exc);
3743 * mono_nullable_init:
3744 * @buf: The nullable structure to initialize.
3745 * @value: the value to initialize from
3746 * @klass: the type for the object
3748 * Initialize the nullable structure pointed to by @buf from @value which
3749 * should be a boxed value type. The size of @buf should be able to hold
3750 * as much data as the @klass->instance_size (which is the number of bytes
3751 * that will be copies).
3753 * Since Nullables have variable structure, we can not define a C
3754 * structure for them.
3757 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3759 MONO_REQ_GC_UNSAFE_MODE;
3761 MonoClass *param_class = klass->cast_class;
3763 mono_class_setup_fields (klass);
3764 g_assert (klass->fields_inited);
3766 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3767 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3769 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3771 if (param_class->has_references)
3772 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3774 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3776 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3781 * mono_nullable_init_from_handle:
3782 * @buf: The nullable structure to initialize.
3783 * @value: the value to initialize from
3784 * @klass: the type for the object
3786 * Initialize the nullable structure pointed to by @buf from @value which
3787 * should be a boxed value type. The size of @buf should be able to hold
3788 * as much data as the @klass->instance_size (which is the number of bytes
3789 * that will be copies).
3791 * Since Nullables have variable structure, we can not define a C
3792 * structure for them.
3795 mono_nullable_init_from_handle (guint8 *buf, MonoObjectHandle value, MonoClass *klass)
3797 MONO_REQ_GC_UNSAFE_MODE;
3799 MonoClass *param_class = klass->cast_class;
3801 mono_class_setup_fields (klass);
3802 g_assert (klass->fields_inited);
3804 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3805 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3807 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = MONO_HANDLE_IS_NULL (value) ? 0 : 1;
3808 if (!MONO_HANDLE_IS_NULL (value)) {
3809 uint32_t value_gchandle = 0;
3810 gpointer src = mono_object_handle_pin_unbox (value, &value_gchandle);
3811 if (param_class->has_references)
3812 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), src, 1, param_class);
3814 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), src, mono_class_value_size (param_class, NULL));
3815 mono_gchandle_free (value_gchandle);
3817 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3824 * mono_nullable_box:
3825 * \param buf The buffer representing the data to be boxed
3826 * \param klass the type to box it as.
3827 * \param error set on error
3829 * Creates a boxed vtype or NULL from the \c Nullable structure pointed to by
3830 * \p buf. On failure returns NULL and sets \p error.
3833 mono_nullable_box (guint8 *buf, MonoClass *klass, MonoError *error)
3835 MONO_REQ_GC_UNSAFE_MODE;
3838 MonoClass *param_class = klass->cast_class;
3840 mono_class_setup_fields (klass);
3841 g_assert (klass->fields_inited);
3843 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3844 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3846 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3847 MonoObject *o = mono_object_new_checked (mono_domain_get (), param_class, error);
3848 return_val_if_nok (error, NULL);
3849 if (param_class->has_references)
3850 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3852 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3860 * mono_get_delegate_invoke:
3861 * \param klass The delegate class
3862 * \returns the \c MonoMethod for the \c Invoke method in the delegate class or NULL if \p klass is a broken delegate type
3865 mono_get_delegate_invoke (MonoClass *klass)
3867 MONO_REQ_GC_NEUTRAL_MODE;
3871 /* This is called at runtime, so avoid the slower search in metadata */
3872 mono_class_setup_methods (klass);
3873 if (mono_class_has_failure (klass))
3875 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3880 * mono_get_delegate_begin_invoke:
3881 * \param klass The delegate class
3882 * \returns the \c MonoMethod for the \c BeginInvoke method in the delegate class or NULL if \p klass is a broken delegate type
3885 mono_get_delegate_begin_invoke (MonoClass *klass)
3887 MONO_REQ_GC_NEUTRAL_MODE;
3891 /* This is called at runtime, so avoid the slower search in metadata */
3892 mono_class_setup_methods (klass);
3893 if (mono_class_has_failure (klass))
3895 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3900 * mono_get_delegate_end_invoke:
3901 * \param klass The delegate class
3902 * \returns the \c MonoMethod for the \c EndInvoke method in the delegate class or NULL if \p klass is a broken delegate type
3905 mono_get_delegate_end_invoke (MonoClass *klass)
3907 MONO_REQ_GC_NEUTRAL_MODE;
3911 /* This is called at runtime, so avoid the slower search in metadata */
3912 mono_class_setup_methods (klass);
3913 if (mono_class_has_failure (klass))
3915 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3920 * mono_runtime_delegate_invoke:
3921 * \param delegate pointer to a delegate object.
3922 * \param params parameters for the delegate.
3923 * \param exc Pointer to the exception result.
3925 * Invokes the delegate method \p delegate with the parameters provided.
3927 * You can pass NULL as the \p exc argument if you don't want to
3928 * catch exceptions, otherwise, \c *exc will be set to the exception
3929 * thrown, if any. if an exception is thrown, you can't use the
3930 * \c MonoObject* result from the function.
3933 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3935 MONO_REQ_GC_UNSAFE_MODE;
3939 MonoObject *result = mono_runtime_delegate_try_invoke (delegate, params, exc, &error);
3941 mono_error_cleanup (&error);
3944 if (!is_ok (&error))
3945 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
3949 MonoObject *result = mono_runtime_delegate_invoke_checked (delegate, params, &error);
3950 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
3956 * mono_runtime_delegate_try_invoke:
3957 * \param delegate pointer to a delegate object.
3958 * \param params parameters for the delegate.
3959 * \param exc Pointer to the exception result.
3960 * \param error set on error
3961 * Invokes the delegate method \p delegate with the parameters provided.
3963 * You can pass NULL as the \p exc argument if you don't want to
3964 * catch exceptions, otherwise, \c *exc will be set to the exception
3965 * thrown, if any. On failure to execute, \p error will be set.
3966 * if an exception is thrown, you can't use the
3967 * \c MonoObject* result from the function.
3970 mono_runtime_delegate_try_invoke (MonoObject *delegate, void **params, MonoObject **exc, MonoError *error)
3972 MONO_REQ_GC_UNSAFE_MODE;
3976 MonoClass *klass = delegate->vtable->klass;
3979 im = mono_get_delegate_invoke (klass);
3981 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3984 o = mono_runtime_try_invoke (im, delegate, params, exc, error);
3986 o = mono_runtime_invoke_checked (im, delegate, params, error);
3993 * mono_runtime_delegate_invoke_checked:
3994 * \param delegate pointer to a delegate object.
3995 * \param params parameters for the delegate.
3996 * \param error set on error
3997 * Invokes the delegate method \p delegate with the parameters provided.
3998 * On failure \p error will be set and you can't use the \c MonoObject*
3999 * result from the function.
4002 mono_runtime_delegate_invoke_checked (MonoObject *delegate, void **params, MonoError *error)
4005 return mono_runtime_delegate_try_invoke (delegate, params, NULL, error);
4008 static char **main_args = NULL;
4009 static int num_main_args = 0;
4012 * mono_runtime_get_main_args:
4013 * \returns A \c MonoArray with the arguments passed to the main program
4016 mono_runtime_get_main_args (void)
4018 MONO_REQ_GC_UNSAFE_MODE;
4020 MonoArray *result = mono_runtime_get_main_args_checked (&error);
4021 mono_error_assert_ok (&error);
4026 * mono_runtime_get_main_args_checked:
4027 * \param error set on error
4028 * \returns a \c MonoArray with the arguments passed to the main
4029 * program. On failure returns NULL and sets \p error.
4032 mono_runtime_get_main_args_checked (MonoError *error)
4036 MonoDomain *domain = mono_domain_get ();
4040 res = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, num_main_args, error);
4041 return_val_if_nok (error, NULL);
4043 for (i = 0; i < num_main_args; ++i) {
4044 MonoString *arg = mono_string_new_checked (domain, main_args [i], error);
4045 return_val_if_nok (error, NULL);
4046 mono_array_setref (res, i, arg);
4053 free_main_args (void)
4055 MONO_REQ_GC_NEUTRAL_MODE;
4059 for (i = 0; i < num_main_args; ++i)
4060 g_free (main_args [i]);
4067 * mono_runtime_set_main_args:
4068 * \param argc number of arguments from the command line
4069 * \param argv array of strings from the command line
4070 * Set the command line arguments from an embedding application that doesn't otherwise call
4071 * \c mono_runtime_run_main.
4074 mono_runtime_set_main_args (int argc, char* argv[])
4076 MONO_REQ_GC_NEUTRAL_MODE;
4081 main_args = g_new0 (char*, argc);
4082 num_main_args = argc;
4084 for (i = 0; i < argc; ++i) {
4087 utf8_arg = mono_utf8_from_external (argv[i]);
4088 if (utf8_arg == NULL) {
4089 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
4090 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4094 main_args [i] = utf8_arg;
4101 * Prepare an array of arguments in order to execute a standard Main()
4102 * method (argc/argv contains the executable name). This method also
4103 * sets the command line argument value needed by System.Environment.
4107 prepare_run_main (MonoMethod *method, int argc, char *argv[])
4109 MONO_REQ_GC_UNSAFE_MODE;
4113 MonoArray *args = NULL;
4114 MonoDomain *domain = mono_domain_get ();
4115 gchar *utf8_fullpath;
4116 MonoMethodSignature *sig;
4118 g_assert (method != NULL);
4120 mono_thread_set_main (mono_thread_current ());
4122 main_args = g_new0 (char*, argc);
4123 num_main_args = argc;
4125 if (!g_path_is_absolute (argv [0])) {
4126 gchar *basename = g_path_get_basename (argv [0]);
4127 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
4131 utf8_fullpath = mono_utf8_from_external (fullpath);
4132 if(utf8_fullpath == NULL) {
4133 /* Printing the arg text will cause glib to
4134 * whinge about "Invalid UTF-8", but at least
4135 * its relevant, and shows the problem text
4138 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
4139 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4146 utf8_fullpath = mono_utf8_from_external (argv[0]);
4147 if(utf8_fullpath == NULL) {
4148 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
4149 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4154 main_args [0] = utf8_fullpath;
4156 for (i = 1; i < argc; ++i) {
4159 utf8_arg=mono_utf8_from_external (argv[i]);
4160 if(utf8_arg==NULL) {
4161 /* Ditto the comment about Invalid UTF-8 here */
4162 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
4163 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4167 main_args [i] = utf8_arg;
4172 sig = mono_method_signature (method);
4174 g_print ("Unable to load Main method.\n");
4178 if (sig->param_count) {
4179 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, argc, &error);
4180 mono_error_assert_ok (&error);
4181 for (i = 0; i < argc; ++i) {
4182 /* The encodings should all work, given that
4183 * we've checked all these args for the
4186 gchar *str = mono_utf8_from_external (argv [i]);
4187 MonoString *arg = mono_string_new_checked (domain, str, &error);
4188 mono_error_assert_ok (&error);
4189 mono_array_setref (args, i, arg);
4193 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, 0, &error);
4194 mono_error_assert_ok (&error);
4197 mono_assembly_set_main (method->klass->image->assembly);
4203 * mono_runtime_run_main:
4204 * \param method the method to start the application with (usually <code>Main</code>)
4205 * \param argc number of arguments from the command line
4206 * \param argv array of strings from the command line
4207 * \param exc excetption results
4208 * Execute a standard \c Main method (\p argc / \p argv contains the
4209 * executable name). This method also sets the command line argument value
4210 * needed by \c System.Environment.
4213 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
4216 MONO_REQ_GC_UNSAFE_MODE;
4219 MonoArray *args = prepare_run_main (method, argc, argv);
4222 res = mono_runtime_try_exec_main (method, args, exc);
4224 res = mono_runtime_exec_main_checked (method, args, &error);
4225 mono_error_raise_exception (&error); /* OK to throw, external only without a better alternative */
4231 * mono_runtime_run_main_checked:
4232 * \param method the method to start the application with (usually \c Main)
4233 * \param argc number of arguments from the command line
4234 * \param argv array of strings from the command line
4235 * \param error set on error
4237 * Execute a standard \c Main method (\p argc / \p argv contains the
4238 * executable name). This method also sets the command line argument value
4239 * needed by \c System.Environment. On failure sets \p error.
4242 mono_runtime_run_main_checked (MonoMethod *method, int argc, char* argv[],
4246 MonoArray *args = prepare_run_main (method, argc, argv);
4247 return mono_runtime_exec_main_checked (method, args, error);
4251 * mono_runtime_try_run_main:
4252 * \param method the method to start the application with (usually \c Main)
4253 * \param argc number of arguments from the command line
4254 * \param argv array of strings from the command line
4255 * \param exc set if \c Main throws an exception
4256 * \param error set if \c Main can't be executed
4257 * Execute a standard \c Main method (\p argc / \p argv contains the executable
4258 * name). This method also sets the command line argument value needed
4259 * by \c System.Environment. On failure sets \p error if Main can't be
4260 * executed or \p exc if it threw an exception.
4263 mono_runtime_try_run_main (MonoMethod *method, int argc, char* argv[],
4267 MonoArray *args = prepare_run_main (method, argc, argv);
4268 return mono_runtime_try_exec_main (method, args, exc);
4273 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4275 static MonoMethod *serialize_method;
4281 if (!serialize_method) {
4282 MonoClass *klass = mono_class_get_remoting_services_class ();
4283 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
4286 if (!serialize_method) {
4291 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
4296 array = mono_runtime_try_invoke (serialize_method, NULL, params, exc, &error);
4297 if (*exc == NULL && !mono_error_ok (&error))
4298 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert serialize_object to MonoError */
4300 mono_error_cleanup (&error);
4309 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4311 MONO_REQ_GC_UNSAFE_MODE;
4313 static MonoMethod *deserialize_method;
4319 if (!deserialize_method) {
4320 MonoClass *klass = mono_class_get_remoting_services_class ();
4321 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
4323 if (!deserialize_method) {
4331 result = mono_runtime_try_invoke (deserialize_method, NULL, params, exc, &error);
4332 if (*exc == NULL && !mono_error_ok (&error))
4333 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert deserialize_object to MonoError */
4335 mono_error_cleanup (&error);
4343 #ifndef DISABLE_REMOTING
4345 make_transparent_proxy (MonoObject *obj, MonoError *error)
4347 MONO_REQ_GC_UNSAFE_MODE;
4349 static MonoMethod *get_proxy_method;
4351 MonoDomain *domain = mono_domain_get ();
4352 MonoRealProxy *real_proxy;
4353 MonoReflectionType *reflection_type;
4354 MonoTransparentProxy *transparent_proxy;
4358 if (!get_proxy_method)
4359 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
4361 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
4363 real_proxy = (MonoRealProxy*) mono_object_new_checked (domain, mono_defaults.real_proxy_class, error);
4364 return_val_if_nok (error, NULL);
4365 reflection_type = mono_type_get_object_checked (domain, &obj->vtable->klass->byval_arg, error);
4366 return_val_if_nok (error, NULL);
4368 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
4369 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
4371 MonoObject *exc = NULL;
4373 transparent_proxy = (MonoTransparentProxy*) mono_runtime_try_invoke (get_proxy_method, real_proxy, NULL, &exc, error);
4374 if (exc != NULL && is_ok (error))
4375 mono_error_set_exception_instance (error, (MonoException*)exc);
4377 return (MonoObject*) transparent_proxy;
4379 #endif /* DISABLE_REMOTING */
4382 * mono_object_xdomain_representation
4383 * \param obj an object
4384 * \param target_domain a domain
4385 * \param error set on error.
4386 * Creates a representation of obj in the domain \p target_domain. This
4387 * is either a copy of \p obj arrived through via serialization and
4388 * deserialization or a proxy, depending on whether the object is
4389 * serializable or marshal by ref. \p obj must not be in \p target_domain.
4390 * If the object cannot be represented in \p target_domain, NULL is
4391 * returned and \p error is set appropriately.
4394 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoError *error)
4396 MONO_REQ_GC_UNSAFE_MODE;
4399 MonoObject *deserialized = NULL;
4401 #ifndef DISABLE_REMOTING
4402 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
4403 deserialized = make_transparent_proxy (obj, error);
4408 gboolean failure = FALSE;
4409 MonoDomain *domain = mono_domain_get ();
4410 MonoObject *serialized;
4411 MonoObject *exc = NULL;
4413 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
4414 serialized = serialize_object (obj, &failure, &exc);
4415 mono_domain_set_internal_with_options (target_domain, FALSE);
4417 deserialized = deserialize_object (serialized, &failure, &exc);
4418 if (domain != target_domain)
4419 mono_domain_set_internal_with_options (domain, FALSE);
4421 mono_error_set_exception_instance (error, (MonoException*)exc);
4424 return deserialized;
4427 /* Used in call_unhandled_exception_delegate */
4429 create_unhandled_exception_eventargs (MonoObject *exc, MonoError *error)
4431 MONO_REQ_GC_UNSAFE_MODE;
4436 MonoMethod *method = NULL;
4437 MonoBoolean is_terminating = TRUE;
4440 klass = mono_class_get_unhandled_exception_event_args_class ();
4441 mono_class_init (klass);
4443 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4444 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
4448 args [1] = &is_terminating;
4450 obj = mono_object_new_checked (mono_domain_get (), klass, error);
4451 return_val_if_nok (error, NULL);
4453 mono_runtime_invoke_checked (method, obj, args, error);
4454 return_val_if_nok (error, NULL);
4459 /* Used in mono_unhandled_exception */
4461 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4462 MONO_REQ_GC_UNSAFE_MODE;
4465 MonoObject *e = NULL;
4467 MonoDomain *current_domain = mono_domain_get ();
4469 if (domain != current_domain)
4470 mono_domain_set_internal_with_options (domain, FALSE);
4472 g_assert (domain == mono_object_domain (domain->domain));
4474 if (mono_object_domain (exc) != domain) {
4476 exc = mono_object_xdomain_representation (exc, domain, &error);
4478 if (!is_ok (&error)) {
4479 MonoError inner_error;
4480 MonoException *serialization_exc = mono_error_convert_to_exception (&error);
4481 exc = mono_object_xdomain_representation ((MonoObject*)serialization_exc, domain, &inner_error);
4482 mono_error_assert_ok (&inner_error);
4484 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4485 "System.Runtime.Serialization", "SerializationException",
4486 "Could not serialize unhandled exception.");
4490 g_assert (mono_object_domain (exc) == domain);
4492 pa [0] = domain->domain;
4493 pa [1] = create_unhandled_exception_eventargs (exc, &error);
4494 mono_error_assert_ok (&error);
4495 mono_runtime_delegate_try_invoke (delegate, pa, &e, &error);
4496 if (!is_ok (&error)) {
4498 e = (MonoObject*)mono_error_convert_to_exception (&error);
4500 mono_error_cleanup (&error);
4503 if (domain != current_domain)
4504 mono_domain_set_internal_with_options (current_domain, FALSE);
4507 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4508 if (!mono_error_ok (&error)) {
4509 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4510 mono_error_cleanup (&error);
4512 g_warning ("exception inside UnhandledException handler: %s\n", msg);
4518 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4521 * mono_runtime_unhandled_exception_policy_set:
4522 * \param policy the new policy
4523 * This is a VM internal routine.
4524 * Sets the runtime policy for handling unhandled exceptions.
4527 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4528 runtime_unhandled_exception_policy = policy;
4532 * mono_runtime_unhandled_exception_policy_get:
4534 * This is a VM internal routine.
4536 * Gets the runtime policy for handling unhandled exceptions.
4538 MonoRuntimeUnhandledExceptionPolicy
4539 mono_runtime_unhandled_exception_policy_get (void) {
4540 return runtime_unhandled_exception_policy;
4544 * mono_unhandled_exception:
4545 * \param exc exception thrown
4546 * This is a VM internal routine.
4548 * We call this function when we detect an unhandled exception
4549 * in the default domain.
4551 * It invokes the \c UnhandledException event in \c AppDomain or prints
4552 * a warning to the console
4555 mono_unhandled_exception (MonoObject *exc_raw)
4558 HANDLE_FUNCTION_ENTER ();
4559 MONO_HANDLE_DCL (MonoObject, exc);
4560 error_init (&error);
4561 mono_unhandled_exception_checked (exc, &error);
4562 mono_error_assert_ok (&error);
4563 HANDLE_FUNCTION_RETURN ();
4567 * mono_unhandled_exception:
4568 * @exc: exception thrown
4570 * This is a VM internal routine.
4572 * We call this function when we detect an unhandled exception
4573 * in the default domain.
4575 * It invokes the * UnhandledException event in AppDomain or prints
4576 * a warning to the console
4579 mono_unhandled_exception_checked (MonoObjectHandle exc, MonoError *error)
4581 MONO_REQ_GC_UNSAFE_MODE;
4584 MonoClassField *field;
4585 MonoDomain *current_domain, *root_domain;
4586 MonoObjectHandle current_appdomain_delegate = MONO_HANDLE_NEW (MonoObject, NULL);
4588 MonoClass *klass = mono_handle_class (exc);
4589 if (mono_class_has_parent (klass, mono_defaults.threadabortexception_class))
4592 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4595 current_domain = mono_domain_get ();
4596 root_domain = mono_get_root_domain ();
4598 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 */
4599 return_if_nok (error);
4600 if (current_domain != root_domain) {
4601 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 */
4602 return_if_nok (error);
4605 if (MONO_HANDLE_IS_NULL (current_appdomain_delegate) && MONO_HANDLE_IS_NULL (root_appdomain_delegate)) {
4606 mono_print_unhandled_exception (MONO_HANDLE_RAW (exc)); /* FIXME use handles for mono_print_unhandled_exception */
4608 /* unhandled exception callbacks must not be aborted */
4609 mono_threads_begin_abort_protected_block ();
4610 if (!MONO_HANDLE_IS_NULL (root_appdomain_delegate))
4611 call_unhandled_exception_delegate (root_domain, MONO_HANDLE_RAW (root_appdomain_delegate), MONO_HANDLE_RAW (exc)); /* FIXME use handles in call_unhandled_exception_delegate */
4612 if (!MONO_HANDLE_IS_NULL (current_appdomain_delegate))
4613 call_unhandled_exception_delegate (current_domain, MONO_HANDLE_RAW (current_appdomain_delegate), MONO_HANDLE_RAW (exc));
4614 mono_threads_end_abort_protected_block ();
4617 /* set exitcode only if we will abort the process */
4618 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4619 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4621 mono_environment_exitcode_set (1);
4626 * mono_runtime_exec_managed_code:
4627 * \param domain Application domain
4628 * \param main_func function to invoke from the execution thread
4629 * \param main_args parameter to the main_func
4630 * Launch a new thread to execute a function
4632 * \p main_func is called back from the thread with main_args as the
4633 * parameter. The callback function is expected to start \c Main
4634 * eventually. This function then waits for all managed threads to
4636 * It is not necessary anymore to execute managed code in a subthread,
4637 * so this function should not be used anymore by default: just
4638 * execute the code and then call mono_thread_manage().
4641 mono_runtime_exec_managed_code (MonoDomain *domain,
4642 MonoMainThreadFunc main_func,
4646 mono_thread_create_checked (domain, main_func, main_args, &error);
4647 mono_error_assert_ok (&error);
4649 mono_thread_manage ();
4653 prepare_thread_to_exec_main (MonoDomain *domain, MonoMethod *method)
4655 MonoInternalThread* thread = mono_thread_internal_current ();
4656 MonoCustomAttrInfo* cinfo;
4657 gboolean has_stathread_attribute;
4659 if (!domain->entry_assembly) {
4662 MonoAssembly *assembly;
4664 assembly = method->klass->image->assembly;
4665 domain->entry_assembly = assembly;
4666 /* Domains created from another domain already have application_base and configuration_file set */
4667 if (domain->setup->application_base == NULL) {
4668 MonoString *basedir = mono_string_new_checked (domain, assembly->basedir, &error);
4669 mono_error_assert_ok (&error);
4670 MONO_OBJECT_SETREF (domain->setup, application_base, basedir);
4673 if (domain->setup->configuration_file == NULL) {
4674 str = g_strconcat (assembly->image->name, ".config", NULL);
4675 MonoString *config_file = mono_string_new_checked (domain, str, &error);
4676 mono_error_assert_ok (&error);
4677 MONO_OBJECT_SETREF (domain->setup, configuration_file, config_file);
4679 mono_domain_set_options_from_config (domain);
4683 MonoError cattr_error;
4684 cinfo = mono_custom_attrs_from_method_checked (method, &cattr_error);
4685 mono_error_cleanup (&cattr_error); /* FIXME warn here? */
4687 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, mono_class_get_sta_thread_attribute_class ());
4689 mono_custom_attrs_free (cinfo);
4691 has_stathread_attribute = FALSE;
4693 if (has_stathread_attribute) {
4694 thread->apartment_state = ThreadApartmentState_STA;
4696 thread->apartment_state = ThreadApartmentState_MTA;
4698 mono_thread_init_apartment_state ();
4703 do_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4705 MONO_REQ_GC_UNSAFE_MODE;
4715 /* FIXME: check signature of method */
4716 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4718 res = mono_runtime_invoke_checked (method, NULL, pa, error);
4720 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4723 mono_environment_exitcode_set (rval);
4725 mono_runtime_invoke_checked (method, NULL, pa, error);
4737 do_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4739 MONO_REQ_GC_UNSAFE_MODE;
4749 /* FIXME: check signature of method */
4750 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4751 MonoError inner_error;
4753 res = mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4754 if (*exc == NULL && !mono_error_ok (&inner_error))
4755 *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4757 mono_error_cleanup (&inner_error);
4760 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4764 mono_environment_exitcode_set (rval);
4766 MonoError inner_error;
4767 mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4768 if (*exc == NULL && !mono_error_ok (&inner_error))
4769 *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4771 mono_error_cleanup (&inner_error);
4776 /* If the return type of Main is void, only
4777 * set the exitcode if an exception was thrown
4778 * (we don't want to blow away an
4779 * explicitly-set exit code)
4782 mono_environment_exitcode_set (rval);
4790 * Execute a standard Main() method (args doesn't contain the
4794 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4797 prepare_thread_to_exec_main (mono_object_domain (args), method);
4799 int rval = do_try_exec_main (method, args, exc);
4802 int rval = do_exec_main_checked (method, args, &error);
4803 mono_error_raise_exception (&error); /* OK to throw, external only with no better option */
4809 * Execute a standard Main() method (args doesn't contain the
4812 * On failure sets @error
4815 mono_runtime_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4818 prepare_thread_to_exec_main (mono_object_domain (args), method);
4819 return do_exec_main_checked (method, args, error);
4823 * Execute a standard Main() method (args doesn't contain the
4826 * On failure sets @error if Main couldn't be executed, or @exc if it threw an exception.
4829 mono_runtime_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4831 prepare_thread_to_exec_main (mono_object_domain (args), method);
4832 return do_try_exec_main (method, args, exc);
4837 /** invoke_array_extract_argument:
4838 * @params: array of arguments to the method.
4839 * @i: the index of the argument to extract.
4840 * @t: ith type from the method signature.
4841 * @has_byref_nullables: outarg - TRUE if method expects a byref nullable argument
4842 * @error: set on error.
4844 * Given an array of method arguments, return the ith one using the corresponding type
4845 * to perform necessary unboxing. If method expects a ref nullable argument, writes TRUE to @has_byref_nullables.
4847 * On failure sets @error and returns NULL.
4850 invoke_array_extract_argument (MonoArray *params, int i, MonoType *t, gboolean* has_byref_nullables, MonoError *error)
4852 MonoType *t_orig = t;
4853 gpointer result = NULL;
4859 case MONO_TYPE_BOOLEAN:
4862 case MONO_TYPE_CHAR:
4871 case MONO_TYPE_VALUETYPE:
4872 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (t_orig))) {
4873 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4874 result = mono_array_get (params, MonoObject*, i);
4876 *has_byref_nullables = TRUE;
4878 /* MS seems to create the objects if a null is passed in */
4879 gboolean was_null = FALSE;
4880 if (!mono_array_get (params, MonoObject*, i)) {
4881 MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (t_orig), error);
4882 return_val_if_nok (error, NULL);
4883 mono_array_setref (params, i, o);
4889 * We can't pass the unboxed vtype byref to the callee, since
4890 * that would mean the callee would be able to modify boxed
4891 * primitive types. So we (and MS) make a copy of the boxed
4892 * object, pass that to the callee, and replace the original
4893 * boxed object in the arg array with the copy.
4895 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4896 MonoObject *copy = mono_value_box_checked (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig), error);
4897 return_val_if_nok (error, NULL);
4898 mono_array_setref (params, i, copy);
4901 result = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4902 if (!t->byref && was_null)
4903 mono_array_setref (params, i, NULL);
4906 case MONO_TYPE_STRING:
4907 case MONO_TYPE_OBJECT:
4908 case MONO_TYPE_CLASS:
4909 case MONO_TYPE_ARRAY:
4910 case MONO_TYPE_SZARRAY:
4912 result = mono_array_addr (params, MonoObject*, i);
4913 // FIXME: I need to check this code path
4915 result = mono_array_get (params, MonoObject*, i);
4917 case MONO_TYPE_GENERICINST:
4919 t = &t->data.generic_class->container_class->this_arg;
4921 t = &t->data.generic_class->container_class->byval_arg;
4923 case MONO_TYPE_PTR: {
4926 /* The argument should be an IntPtr */
4927 arg = mono_array_get (params, MonoObject*, i);
4931 g_assert (arg->vtable->klass == mono_defaults.int_class);
4932 result = ((MonoIntPtr*)arg)->m_value;
4937 g_error ("type 0x%x not handled in mono_runtime_invoke_array", t_orig->type);
4942 * mono_runtime_invoke_array:
4943 * \param method method to invoke
4944 * \param obj object instance
4945 * \param params arguments to the method
4946 * \param exc exception information.
4947 * Invokes the method represented by \p method on the object \p obj.
4949 * \p obj is the \c this pointer, it should be NULL for static
4950 * methods, a \c MonoObject* for object instances and a pointer to
4951 * the value type for value types.
4953 * The \p params array contains the arguments to the method with the
4954 * same convention: \c MonoObject* pointers for object instances and
4955 * pointers to the value type otherwise. The \c _invoke_array
4956 * variant takes a C# \c object[] as the params argument (\c MonoArray*):
4957 * in this case the value types are boxed inside the
4958 * respective reference representation.
4960 * From unmanaged code you'll usually use the
4961 * mono_runtime_invoke_checked() variant.
4963 * Note that this function doesn't handle virtual methods for
4964 * you, it will exec the exact method you pass: we still need to
4965 * expose a function to lookup the derived class implementation
4966 * of a virtual method (there are examples of this in the code,
4969 * You can pass NULL as the \p exc argument if you don't want to
4970 * catch exceptions, otherwise, \c *exc will be set to the exception
4971 * thrown, if any. if an exception is thrown, you can't use the
4972 * \c MonoObject* result from the function.
4974 * If the method returns a value type, it is boxed in an object
4978 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4983 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, exc, &error);
4985 mono_error_cleanup (&error);
4988 if (!is_ok (&error))
4989 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
4993 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, NULL, &error);
4994 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
5000 * mono_runtime_invoke_array_checked:
5001 * \param method method to invoke
5002 * \param obj object instance
5003 * \param params arguments to the method
5004 * \param error set on failure.
5005 * Invokes the method represented by \p method on the object \p obj.
5007 * \p obj is the \c this pointer, it should be NULL for static
5008 * methods, a \c MonoObject* for object instances and a pointer to
5009 * the value type for value types.
5011 * The \p params array contains the arguments to the method with the
5012 * same convention: \c MonoObject* pointers for object instances and
5013 * pointers to the value type otherwise. The \c _invoke_array
5014 * variant takes a C# \c object[] as the \p params argument (\c MonoArray*):
5015 * in this case the value types are boxed inside the
5016 * respective reference representation.
5018 * From unmanaged code you'll usually use the
5019 * mono_runtime_invoke_checked() variant.
5021 * Note that this function doesn't handle virtual methods for
5022 * you, it will exec the exact method you pass: we still need to
5023 * expose a function to lookup the derived class implementation
5024 * of a virtual method (there are examples of this in the code,
5027 * On failure or exception, \p error will be set. In that case, you
5028 * can't use the \c MonoObject* result from the function.
5030 * If the method returns a value type, it is boxed in an object
5034 mono_runtime_invoke_array_checked (MonoMethod *method, void *obj, MonoArray *params,
5038 return mono_runtime_try_invoke_array (method, obj, params, NULL, error);
5042 * mono_runtime_try_invoke_array:
5043 * \param method method to invoke
5044 * \param obj object instance
5045 * \param params arguments to the method
5046 * \param exc exception information.
5047 * \param error set on failure.
5048 * Invokes the method represented by \p method on the object \p obj.
5050 * \p obj is the \c this pointer, it should be NULL for static
5051 * methods, a \c MonoObject* for object instances and a pointer to
5052 * the value type for value types.
5054 * The \p params array contains the arguments to the method with the
5055 * same convention: \c MonoObject* pointers for object instances and
5056 * pointers to the value type otherwise. The \c _invoke_array
5057 * variant takes a C# \c object[] as the params argument (\c MonoArray*):
5058 * in this case the value types are boxed inside the
5059 * respective reference representation.
5061 * From unmanaged code you'll usually use the
5062 * mono_runtime_invoke_checked() variant.
5064 * Note that this function doesn't handle virtual methods for
5065 * you, it will exec the exact method you pass: we still need to
5066 * expose a function to lookup the derived class implementation
5067 * of a virtual method (there are examples of this in the code,
5070 * You can pass NULL as the \p exc argument if you don't want to catch
5071 * exceptions, otherwise, \c *exc will be set to the exception thrown, if
5072 * any. On other failures, \p error will be set. If an exception is
5073 * thrown or there's an error, you can't use the \c MonoObject* result
5074 * from the function.
5076 * If the method returns a value type, it is boxed in an object
5080 mono_runtime_try_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
5081 MonoObject **exc, MonoError *error)
5083 MONO_REQ_GC_UNSAFE_MODE;
5087 MonoMethodSignature *sig = mono_method_signature (method);
5088 gpointer *pa = NULL;
5091 gboolean has_byref_nullables = FALSE;
5093 if (NULL != params) {
5094 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
5095 for (i = 0; i < mono_array_length (params); i++) {
5096 MonoType *t = sig->params [i];
5097 pa [i] = invoke_array_extract_argument (params, i, t, &has_byref_nullables, error);
5098 return_val_if_nok (error, NULL);
5102 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
5105 if (mono_class_is_nullable (method->klass)) {
5106 /* Need to create a boxed vtype instead */
5112 return mono_value_box_checked (mono_domain_get (), method->klass->cast_class, pa [0], error);
5117 obj = mono_object_new_checked (mono_domain_get (), method->klass, error);
5118 mono_error_assert_ok (error);
5119 g_assert (obj); /*maybe we should raise a TLE instead?*/
5120 #ifndef DISABLE_REMOTING
5121 if (mono_object_is_transparent_proxy (obj)) {
5122 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
5125 if (method->klass->valuetype)
5126 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
5129 } else if (method->klass->valuetype) {
5130 obj = mono_value_box_checked (mono_domain_get (), method->klass, obj, error);
5131 return_val_if_nok (error, NULL);
5135 mono_runtime_try_invoke (method, o, pa, exc, error);
5137 mono_runtime_invoke_checked (method, o, pa, error);
5140 return (MonoObject *)obj;
5142 if (mono_class_is_nullable (method->klass)) {
5143 MonoObject *nullable;
5145 /* Convert the unboxed vtype into a Nullable structure */
5146 nullable = mono_object_new_checked (mono_domain_get (), method->klass, error);
5147 return_val_if_nok (error, NULL);
5149 MonoObject *boxed = mono_value_box_checked (mono_domain_get (), method->klass->cast_class, obj, error);
5150 return_val_if_nok (error, NULL);
5151 mono_nullable_init ((guint8 *)mono_object_unbox (nullable), boxed, method->klass);
5152 obj = mono_object_unbox (nullable);
5155 /* obj must be already unboxed if needed */
5157 res = mono_runtime_try_invoke (method, obj, pa, exc, error);
5159 res = mono_runtime_invoke_checked (method, obj, pa, error);
5161 return_val_if_nok (error, NULL);
5163 if (sig->ret->type == MONO_TYPE_PTR) {
5164 MonoClass *pointer_class;
5165 static MonoMethod *box_method;
5167 MonoObject *box_exc;
5170 * The runtime-invoke wrapper returns a boxed IntPtr, need to
5171 * convert it to a Pointer object.
5173 pointer_class = mono_class_get_pointer_class ();
5175 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
5177 g_assert (res->vtable->klass == mono_defaults.int_class);
5178 box_args [0] = ((MonoIntPtr*)res)->m_value;
5179 box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, error);
5180 return_val_if_nok (error, NULL);
5182 res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, error);
5183 g_assert (box_exc == NULL);
5184 mono_error_assert_ok (error);
5187 if (has_byref_nullables) {
5189 * The runtime invoke wrapper already converted byref nullables back,
5190 * and stored them in pa, we just need to copy them back to the
5193 for (i = 0; i < mono_array_length (params); i++) {
5194 MonoType *t = sig->params [i];
5196 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
5197 mono_array_setref (params, i, pa [i]);
5207 * \param klass the class of the object that we want to create
5208 * \returns a newly created object whose definition is
5209 * looked up using \p klass. This will not invoke any constructors,
5210 * so the consumer of this routine has to invoke any constructors on
5211 * its own to initialize the object.
5213 * It returns NULL on failure.
5216 mono_object_new (MonoDomain *domain, MonoClass *klass)
5218 MONO_REQ_GC_UNSAFE_MODE;
5222 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5224 mono_error_cleanup (&error);
5229 ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
5231 MONO_REQ_GC_UNSAFE_MODE;
5235 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5237 mono_error_set_pending_exception (&error);
5242 * mono_object_new_checked:
5243 * \param klass the class of the object that we want to create
5244 * \param error set on error
5245 * \returns a newly created object whose definition is
5246 * looked up using \p klass. This will not invoke any constructors,
5247 * so the consumer of this routine has to invoke any constructors on
5248 * its own to initialize the object.
5250 * It returns NULL on failure and sets \p error.
5253 mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
5255 MONO_REQ_GC_UNSAFE_MODE;
5259 vtable = mono_class_vtable (domain, klass);
5260 g_assert (vtable); /* FIXME don't swallow the error */
5262 MonoObject *o = mono_object_new_specific_checked (vtable, error);
5267 * mono_object_new_pinned:
5269 * Same as mono_object_new, but the returned object will be pinned.
5270 * For SGEN, these objects will only be freed at appdomain unload.
5273 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
5275 MONO_REQ_GC_UNSAFE_MODE;
5281 vtable = mono_class_vtable (domain, klass);
5282 g_assert (vtable); /* FIXME don't swallow the error */
5284 MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
5286 if (G_UNLIKELY (!o))
5287 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
5288 else if (G_UNLIKELY (vtable->klass->has_finalize))
5289 mono_object_register_finalizer (o);
5295 * mono_object_new_specific:
5296 * \param vtable the vtable of the object that we want to create
5297 * \returns A newly created object with class and domain specified
5301 mono_object_new_specific (MonoVTable *vtable)
5304 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5305 mono_error_cleanup (&error);
5311 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
5313 MONO_REQ_GC_UNSAFE_MODE;
5319 /* check for is_com_object for COM Interop */
5320 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
5323 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
5326 MonoClass *klass = mono_class_get_activation_services_class ();
5329 mono_class_init (klass);
5331 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
5333 mono_error_set_not_supported (error, "Linked away.");
5336 vtable->domain->create_proxy_for_type_method = im;
5339 pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
5340 if (!mono_error_ok (error))
5343 o = mono_runtime_invoke_checked (im, NULL, pa, error);
5344 if (!mono_error_ok (error))
5351 return mono_object_new_alloc_specific_checked (vtable, error);
5355 ves_icall_object_new_specific (MonoVTable *vtable)
5358 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5359 mono_error_set_pending_exception (&error);
5365 * mono_object_new_alloc_specific:
5366 * \param vtable virtual table for the object.
5367 * This function allocates a new \c MonoObject with the type derived
5368 * from the \p vtable information. If the class of this object has a
5369 * finalizer, then the object will be tracked for finalization.
5371 * This method might raise an exception on errors. Use the
5372 * \c mono_object_new_fast_checked method if you want to manually raise
5375 * \returns the allocated object.
5378 mono_object_new_alloc_specific (MonoVTable *vtable)
5381 MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
5382 mono_error_cleanup (&error);
5388 * mono_object_new_alloc_specific_checked:
5389 * \param vtable virtual table for the object.
5390 * \param error holds the error return value.
5392 * This function allocates a new \c MonoObject with the type derived
5393 * from the \p vtable information. If the class of this object has a
5394 * finalizer, then the object will be tracked for finalization.
5396 * If there is not enough memory, the \p error parameter will be set
5397 * and will contain a user-visible message with the amount of bytes
5398 * that were requested.
5400 * \returns the allocated object, or NULL if there is not enough memory
5403 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
5405 MONO_REQ_GC_UNSAFE_MODE;
5411 o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5413 if (G_UNLIKELY (!o))
5414 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5415 else if (G_UNLIKELY (vtable->klass->has_finalize))
5416 mono_object_register_finalizer (o);
5422 * mono_object_new_fast:
5423 * \param vtable virtual table for the object.
5425 * This function allocates a new \c MonoObject with the type derived
5426 * from the \p vtable information. The returned object is not tracked
5427 * for finalization. If your object implements a finalizer, you should
5428 * use \c mono_object_new_alloc_specific instead.
5430 * This method might raise an exception on errors. Use the
5431 * \c mono_object_new_fast_checked method if you want to manually raise
5434 * \returns the allocated object.
5437 mono_object_new_fast (MonoVTable *vtable)
5440 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5441 mono_error_cleanup (&error);
5447 * mono_object_new_fast_checked:
5448 * \param vtable virtual table for the object.
5449 * \param error holds the error return value.
5451 * This function allocates a new \c MonoObject with the type derived
5452 * from the \p vtable information. The returned object is not tracked
5453 * for finalization. If your object implements a finalizer, you should
5454 * use \c mono_object_new_alloc_specific_checked instead.
5456 * If there is not enough memory, the \p error parameter will be set
5457 * and will contain a user-visible message with the amount of bytes
5458 * that were requested.
5460 * \returns the allocated object, or NULL if there is not enough memory
5463 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
5465 MONO_REQ_GC_UNSAFE_MODE;
5471 o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5473 if (G_UNLIKELY (!o))
5474 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5480 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
5482 MONO_REQ_GC_UNSAFE_MODE;
5488 o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
5490 if (G_UNLIKELY (!o))
5491 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5492 else if (G_UNLIKELY (vtable->klass->has_finalize))
5493 mono_object_register_finalizer (o);
5499 * mono_object_new_from_token:
5500 * \param image Context where the type_token is hosted
5501 * \param token a token of the type that we want to create
5502 * \returns A newly created object whose definition is
5503 * looked up using \p token in the \p image image
5506 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
5508 MONO_REQ_GC_UNSAFE_MODE;
5514 klass = mono_class_get_checked (image, token, &error);
5515 mono_error_assert_ok (&error);
5517 result = mono_object_new_checked (domain, klass, &error);
5519 mono_error_cleanup (&error);
5526 * mono_object_clone:
5527 * \param obj the object to clone
5528 * \returns A newly created object who is a shallow copy of \p obj
5531 mono_object_clone (MonoObject *obj)
5534 MonoObject *o = mono_object_clone_checked (obj, &error);
5535 mono_error_cleanup (&error);
5541 mono_object_clone_checked (MonoObject *obj, MonoError *error)
5543 MONO_REQ_GC_UNSAFE_MODE;
5550 size = obj->vtable->klass->instance_size;
5552 if (obj->vtable->klass->rank)
5553 return (MonoObject*)mono_array_clone_checked ((MonoArray*)obj, error);
5555 o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
5557 if (G_UNLIKELY (!o)) {
5558 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5562 /* If the object doesn't contain references this will do a simple memmove. */
5563 mono_gc_wbarrier_object_copy (o, obj);
5565 if (obj->vtable->klass->has_finalize)
5566 mono_object_register_finalizer (o);
5571 * mono_array_full_copy:
5572 * \param src source array to copy
5573 * \param dest destination array
5574 * Copies the content of one array to another with exactly the same type and size.
5577 mono_array_full_copy (MonoArray *src, MonoArray *dest)
5579 MONO_REQ_GC_UNSAFE_MODE;
5582 MonoClass *klass = src->obj.vtable->klass;
5584 g_assert (klass == dest->obj.vtable->klass);
5586 size = mono_array_length (src);
5587 g_assert (size == mono_array_length (dest));
5588 size *= mono_array_element_size (klass);
5590 array_full_copy_unchecked_size (src, dest, klass, size);
5594 array_full_copy_unchecked_size (MonoArray *src, MonoArray *dest, MonoClass *klass, uintptr_t size)
5596 if (mono_gc_is_moving ()) {
5597 if (klass->element_class->valuetype) {
5598 if (klass->element_class->has_references)
5599 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
5601 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5603 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
5606 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5611 * mono_array_clone_in_domain:
5612 * \param domain the domain in which the array will be cloned into
5613 * \param array the array to clone
5614 * \param error set on error
5615 * This routine returns a copy of the array that is hosted on the
5616 * specified \c MonoDomain. On failure returns NULL and sets \p error.
5619 mono_array_clone_in_domain (MonoDomain *domain, MonoArrayHandle array_handle, MonoError *error)
5621 MONO_REQ_GC_UNSAFE_MODE;
5623 MonoArrayHandle result = MONO_HANDLE_NEW (MonoArray, NULL);
5625 MonoClass *klass = mono_handle_class (array_handle);
5629 /* Pin source array here - if bounds is non-NULL, it's a pointer into the object data */
5630 uint32_t src_handle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, array_handle), TRUE);
5632 MonoArrayBounds *array_bounds = MONO_HANDLE_GETVAL (array_handle, bounds);
5634 if (array_bounds == NULL) {
5635 size = mono_array_handle_length (array_handle);
5636 o = mono_array_new_full_handle (domain, klass, &size, NULL, error);
5639 size *= mono_array_element_size (klass);
5641 uintptr_t *sizes = (uintptr_t *)alloca (klass->rank * sizeof (uintptr_t));
5642 intptr_t *lower_bounds = (intptr_t *)alloca (klass->rank * sizeof (intptr_t));
5643 size = mono_array_element_size (klass);
5644 for (int i = 0; i < klass->rank; ++i) {
5645 sizes [i] = array_bounds [i].length;
5646 size *= array_bounds [i].length;
5647 lower_bounds [i] = array_bounds [i].lower_bound;
5649 o = mono_array_new_full_handle (domain, klass, sizes, lower_bounds, error);
5654 uint32_t dst_handle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, o), TRUE);
5655 array_full_copy_unchecked_size (MONO_HANDLE_RAW (array_handle), MONO_HANDLE_RAW (o), klass, size);
5656 mono_gchandle_free (dst_handle);
5658 MONO_HANDLE_ASSIGN (result, o);
5661 mono_gchandle_free (src_handle);
5667 * \param array the array to clone
5668 * \returns A newly created array who is a shallow copy of \p array
5671 mono_array_clone (MonoArray *array)
5673 MONO_REQ_GC_UNSAFE_MODE;
5676 MonoArray *result = mono_array_clone_checked (array, &error);
5677 mono_error_cleanup (&error);
5682 * mono_array_clone_checked:
5683 * \param array the array to clone
5684 * \param error set on error
5685 * \returns A newly created array who is a shallow copy of \p array. On
5686 * failure returns NULL and sets \p error.
5689 mono_array_clone_checked (MonoArray *array_raw, MonoError *error)
5691 MONO_REQ_GC_UNSAFE_MODE;
5692 HANDLE_FUNCTION_ENTER ();
5693 /* FIXME: callers of mono_array_clone_checked should use handles */
5695 MONO_HANDLE_DCL (MonoArray, array);
5696 MonoArrayHandle result = mono_array_clone_in_domain (MONO_HANDLE_DOMAIN (array), array, error);
5697 HANDLE_FUNCTION_RETURN_OBJ (result);
5700 /* helper macros to check for overflow when calculating the size of arrays */
5701 #ifdef MONO_BIG_ARRAYS
5702 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
5703 #define MYGUINT_MAX MYGUINT64_MAX
5704 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5705 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
5706 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5707 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
5708 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
5710 #define MYGUINT32_MAX 4294967295U
5711 #define MYGUINT_MAX MYGUINT32_MAX
5712 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5713 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
5714 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5715 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
5716 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
5720 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
5722 MONO_REQ_GC_NEUTRAL_MODE;
5726 byte_len = mono_array_element_size (klass);
5727 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
5730 if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
5732 byte_len += MONO_SIZEOF_MONO_ARRAY;
5740 * mono_array_new_full:
5741 * \param domain domain where the object is created
5742 * \param array_class array class
5743 * \param lengths lengths for each dimension in the array
5744 * \param lower_bounds lower bounds for each dimension in the array (may be NULL)
5745 * This routine creates a new array object with the given dimensions,
5746 * lower bounds and type.
5749 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
5752 MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
5753 mono_error_cleanup (&error);
5759 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
5761 MONO_REQ_GC_UNSAFE_MODE;
5763 uintptr_t byte_len = 0, len, bounds_size;
5766 MonoArrayBounds *bounds;
5772 if (!array_class->inited)
5773 mono_class_init (array_class);
5777 /* A single dimensional array with a 0 lower bound is the same as an szarray */
5778 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
5780 if (len > MONO_ARRAY_MAX_INDEX) {
5781 mono_error_set_generic_error (error, "System", "OverflowException", "");
5786 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
5788 for (i = 0; i < array_class->rank; ++i) {
5789 if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
5790 mono_error_set_generic_error (error, "System", "OverflowException", "");
5793 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5794 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5801 if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5802 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5808 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5809 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5812 byte_len = (byte_len + 3) & ~3;
5813 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5814 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5817 byte_len += bounds_size;
5820 * Following three lines almost taken from mono_object_new ():
5821 * they need to be kept in sync.
5823 vtable = mono_class_vtable_full (domain, array_class, error);
5824 return_val_if_nok (error, NULL);
5827 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5829 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5831 if (G_UNLIKELY (!o)) {
5832 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5836 array = (MonoArray*)o;
5838 bounds = array->bounds;
5841 for (i = 0; i < array_class->rank; ++i) {
5842 bounds [i].length = lengths [i];
5844 bounds [i].lower_bound = lower_bounds [i];
5853 * \param domain domain where the object is created
5854 * \param eclass element class
5855 * \param n number of array elements
5856 * This routine creates a new szarray with \p n elements of type \p eclass.
5859 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5861 MONO_REQ_GC_UNSAFE_MODE;
5864 MonoArray *result = mono_array_new_checked (domain, eclass, n, &error);
5865 mono_error_cleanup (&error);
5870 * mono_array_new_checked:
5871 * \param domain domain where the object is created
5872 * \param eclass element class
5873 * \param n number of array elements
5874 * \param error set on error
5875 * This routine creates a new szarray with \p n elements of type \p eclass.
5876 * On failure returns NULL and sets \p error.
5879 mono_array_new_checked (MonoDomain *domain, MonoClass *eclass, uintptr_t n, MonoError *error)
5885 ac = mono_array_class_get (eclass, 1);
5888 MonoVTable *vtable = mono_class_vtable_full (domain, ac, error);
5889 return_val_if_nok (error, NULL);
5891 return mono_array_new_specific_checked (vtable, n, error);
5895 ves_icall_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5898 MonoArray *arr = mono_array_new_checked (domain, eclass, n, &error);
5899 mono_error_set_pending_exception (&error);
5905 * mono_array_new_specific:
5906 * \param vtable a vtable in the appropriate domain for an initialized class
5907 * \param n number of array elements
5908 * This routine is a fast alternative to \c mono_array_new for code which
5909 * can be sure about the domain it operates in.
5912 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5915 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5916 mono_error_cleanup (&error);
5922 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
5924 MONO_REQ_GC_UNSAFE_MODE;
5931 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
5932 mono_error_set_generic_error (error, "System", "OverflowException", "");
5936 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
5937 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5940 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
5942 if (G_UNLIKELY (!o)) {
5943 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5947 return (MonoArray*)o;
5951 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
5954 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5955 mono_error_set_pending_exception (&error);
5961 * mono_string_empty_wrapper:
5963 * Returns: The same empty string instance as the managed string.Empty
5966 mono_string_empty_wrapper (void)
5968 MonoDomain *domain = mono_domain_get ();
5969 return mono_string_empty (domain);
5973 * mono_string_empty:
5975 * Returns: The same empty string instance as the managed string.Empty
5978 mono_string_empty (MonoDomain *domain)
5981 g_assert (domain->empty_string);
5982 return domain->empty_string;
5986 * mono_string_new_utf16:
5987 * \param text a pointer to an utf16 string
5988 * \param len the length of the string
5989 * \returns A newly created string object which contains \p text.
5992 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
5994 MONO_REQ_GC_UNSAFE_MODE;
5997 MonoString *res = NULL;
5998 res = mono_string_new_utf16_checked (domain, text, len, &error);
5999 mono_error_cleanup (&error);
6005 * mono_string_new_utf16_checked:
6006 * \param text a pointer to an utf16 string
6007 * \param len the length of the string
6008 * \param error written on error.
6009 * \returns A newly created string object which contains \p text.
6010 * On error, returns NULL and sets \p error.
6013 mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
6015 MONO_REQ_GC_UNSAFE_MODE;
6021 s = mono_string_new_size_checked (domain, len, error);
6023 memcpy (mono_string_chars (s), text, len * 2);
6029 * mono_string_new_utf16_handle:
6030 * \param text a pointer to an utf16 string
6031 * \param len the length of the string
6032 * \param error written on error.
6033 * \returns A newly created string object which contains \p text.
6034 * On error, returns NULL and sets \p error.
6037 mono_string_new_utf16_handle (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
6039 return MONO_HANDLE_NEW (MonoString, mono_string_new_utf16_checked (domain, text, len, error));
6043 * mono_string_new_utf32_checked:
6044 * \param text a pointer to an utf32 string
6045 * \param len the length of the string
6046 * \param error set on failure.
6047 * \returns A newly created string object which contains \p text. On failure returns NULL and sets \p error.
6050 mono_string_new_utf32_checked (MonoDomain *domain, const mono_unichar4 *text, gint32 len, MonoError *error)
6052 MONO_REQ_GC_UNSAFE_MODE;
6055 mono_unichar2 *utf16_output = NULL;
6056 gint32 utf16_len = 0;
6057 GError *gerror = NULL;
6058 glong items_written;
6061 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
6064 g_error_free (gerror);
6066 while (utf16_output [utf16_len]) utf16_len++;
6068 s = mono_string_new_size_checked (domain, utf16_len, error);
6069 return_val_if_nok (error, NULL);
6071 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
6073 g_free (utf16_output);
6079 * mono_string_new_utf32:
6080 * \param text a pointer to a UTF-32 string
6081 * \param len the length of the string
6082 * \returns A newly created string object which contains \p text.
6085 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
6088 MonoString *result = mono_string_new_utf32_checked (domain, text, len, &error);
6089 mono_error_cleanup (&error);
6094 * mono_string_new_size:
6095 * \param text a pointer to a UTF-16 string
6096 * \param len the length of the string
6097 * \returns A newly created string object of \p len
6100 mono_string_new_size (MonoDomain *domain, gint32 len)
6103 MonoString *str = mono_string_new_size_checked (domain, len, &error);
6104 mono_error_cleanup (&error);
6110 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
6112 MONO_REQ_GC_UNSAFE_MODE;
6120 /* check for overflow */
6121 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
6122 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
6126 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
6127 g_assert (size > 0);
6129 vtable = mono_class_vtable (domain, mono_defaults.string_class);
6132 s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
6134 if (G_UNLIKELY (!s)) {
6135 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", size);
6143 * mono_string_new_len:
6144 * \param text a pointer to an utf8 string
6145 * \param length number of bytes in \p text to consider
6146 * \returns A newly created string object which contains \p text.
6149 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
6151 MONO_REQ_GC_UNSAFE_MODE;
6154 MonoString *result = mono_string_new_len_checked (domain, text, length, &error);
6155 mono_error_cleanup (&error);
6160 * mono_string_new_len_checked:
6161 * \param text a pointer to an utf8 string
6162 * \param length number of bytes in \p text to consider
6163 * \param error set on error
6164 * \returns A newly created string object which contains \p text. On
6165 * failure returns NULL and sets \p error.
6168 mono_string_new_len_checked (MonoDomain *domain, const char *text, guint length, MonoError *error)
6170 MONO_REQ_GC_UNSAFE_MODE;
6174 GError *eg_error = NULL;
6175 MonoString *o = NULL;
6177 glong items_written;
6179 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
6182 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6184 g_error_free (eg_error);
6193 * \param text a pointer to a UTF-8 string
6194 * \deprecated Use \c mono_string_new_checked in new code.
6195 * This function asserts if it cannot allocate a new string.
6196 * \returns A newly created string object which contains \p text.
6199 mono_string_new (MonoDomain *domain, const char *text)
6202 MonoString *res = NULL;
6203 res = mono_string_new_checked (domain, text, &error);
6204 mono_error_assert_ok (&error);
6209 * mono_string_new_checked:
6210 * \param text a pointer to an utf8 string
6211 * \param merror set on error
6212 * \returns A newly created string object which contains \p text.
6213 * On error returns NULL and sets \p merror.
6216 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
6218 MONO_REQ_GC_UNSAFE_MODE;
6220 GError *eg_error = NULL;
6221 MonoString *o = NULL;
6223 glong items_written;
6230 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &eg_error);
6233 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6235 mono_error_set_execution_engine (error, "String conversion error: %s", eg_error->message);
6240 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
6245 MonoString *o = NULL;
6247 if (!g_utf8_validate (text, -1, &end)) {
6248 mono_error_set_argument (error, "text", "Not a valid utf8 string");
6252 len = g_utf8_strlen (text, -1);
6253 o = mono_string_new_size_checked (domain, len, error);
6256 str = mono_string_chars (o);
6258 while (text < end) {
6259 *str++ = g_utf8_get_char (text);
6260 text = g_utf8_next_char (text);
6269 * mono_string_new_wrapper:
6270 * \param text pointer to UTF-8 characters.
6271 * Helper function to create a string object from \p text in the current domain.
6274 mono_string_new_wrapper (const char *text)
6276 MONO_REQ_GC_UNSAFE_MODE;
6278 MonoDomain *domain = mono_domain_get ();
6282 MonoString *result = mono_string_new_checked (domain, text, &error);
6283 mono_error_assert_ok (&error);
6292 * \param class the class of the value
6293 * \param value a pointer to the unboxed data
6294 * \returns A newly created object which contains \p value.
6297 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
6300 MonoObject *result = mono_value_box_checked (domain, klass, value, &error);
6301 mono_error_cleanup (&error);
6306 * mono_value_box_checked:
6307 * \param domain the domain of the new object
6308 * \param class the class of the value
6309 * \param value a pointer to the unboxed data
6310 * \param error set on error
6311 * \returns A newly created object which contains \p value. On failure
6312 * returns NULL and sets \p error.
6315 mono_value_box_checked (MonoDomain *domain, MonoClass *klass, gpointer value, MonoError *error)
6317 MONO_REQ_GC_UNSAFE_MODE;
6324 g_assert (klass->valuetype);
6325 if (mono_class_is_nullable (klass))
6326 return mono_nullable_box ((guint8 *)value, klass, error);
6328 vtable = mono_class_vtable (domain, klass);
6331 size = mono_class_instance_size (klass);
6332 res = mono_object_new_alloc_specific_checked (vtable, error);
6333 return_val_if_nok (error, NULL);
6335 size = size - sizeof (MonoObject);
6337 if (mono_gc_is_moving ()) {
6338 g_assert (size == mono_class_value_size (klass, NULL));
6339 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
6341 #if NO_UNALIGNED_ACCESS
6342 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6346 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
6349 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
6352 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
6355 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
6358 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6362 if (klass->has_finalize) {
6363 mono_object_register_finalizer (res);
6364 return_val_if_nok (error, NULL);
6371 * \param dest destination pointer
6372 * \param src source pointer
6373 * \param klass a valuetype class
6374 * Copy a valuetype from \p src to \p dest. This function must be used
6375 * when \p klass contains reference fields.
6378 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
6380 MONO_REQ_GC_UNSAFE_MODE;
6382 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
6386 * mono_value_copy_array:
6387 * \param dest destination array
6388 * \param dest_idx index in the \p dest array
6389 * \param src source pointer
6390 * \param count number of items
6391 * Copy \p count valuetype items from \p src to the array \p dest at index \p dest_idx.
6392 * This function must be used when \p klass contains references fields.
6393 * Overlap is handled.
6396 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
6398 MONO_REQ_GC_UNSAFE_MODE;
6400 int size = mono_array_element_size (dest->obj.vtable->klass);
6401 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
6402 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
6403 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
6407 * mono_object_get_domain:
6408 * \param obj object to query
6409 * \returns the \c MonoDomain where the object is hosted
6412 mono_object_get_domain (MonoObject *obj)
6414 MONO_REQ_GC_UNSAFE_MODE;
6416 return mono_object_domain (obj);
6420 * mono_object_get_class:
6421 * \param obj object to query
6422 * Use this function to obtain the \c MonoClass* for a given \c MonoObject.
6423 * \returns the \c MonoClass of the object.
6426 mono_object_get_class (MonoObject *obj)
6428 MONO_REQ_GC_UNSAFE_MODE;
6430 return mono_object_class (obj);
6433 * mono_object_get_size:
6434 * \param o object to query
6435 * \returns the size, in bytes, of \p o
6438 mono_object_get_size (MonoObject* o)
6440 MONO_REQ_GC_UNSAFE_MODE;
6442 MonoClass* klass = mono_object_class (o);
6443 if (klass == mono_defaults.string_class) {
6444 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
6445 } else if (o->vtable->rank) {
6446 MonoArray *array = (MonoArray*)o;
6447 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
6448 if (array->bounds) {
6451 size += sizeof (MonoArrayBounds) * o->vtable->rank;
6455 return mono_class_instance_size (klass);
6460 * mono_object_unbox:
6461 * \param obj object to unbox
6462 * \returns a pointer to the start of the valuetype boxed in this
6465 * This method will assert if the object passed is not a valuetype.
6468 mono_object_unbox (MonoObject *obj)
6470 MONO_REQ_GC_UNSAFE_MODE;
6472 /* add assert for valuetypes? */
6473 g_assert (obj->vtable->klass->valuetype);
6474 return ((char*)obj) + sizeof (MonoObject);
6478 * mono_object_isinst:
6479 * \param obj an object
6480 * \param klass a pointer to a class
6481 * \returns \p obj if \p obj is derived from \p klass or NULL otherwise.
6484 mono_object_isinst (MonoObject *obj_raw, MonoClass *klass)
6486 MONO_REQ_GC_UNSAFE_MODE;
6488 HANDLE_FUNCTION_ENTER ();
6489 MONO_HANDLE_DCL (MonoObject, obj);
6491 MonoObjectHandle result = mono_object_handle_isinst (obj, klass, &error);
6492 mono_error_cleanup (&error);
6493 HANDLE_FUNCTION_RETURN_OBJ (result);
6498 * mono_object_isinst_checked:
6499 * \param obj an object
6500 * \param klass a pointer to a class
6501 * \param error set on error
6502 * \returns \p obj if \p obj is derived from \p klass or NULL if it isn't.
6503 * On failure returns NULL and sets \p error.
6506 mono_object_isinst_checked (MonoObject *obj_raw, MonoClass *klass, MonoError *error)
6508 MONO_REQ_GC_UNSAFE_MODE;
6510 HANDLE_FUNCTION_ENTER ();
6512 MONO_HANDLE_DCL (MonoObject, obj);
6513 MonoObjectHandle result = mono_object_handle_isinst (obj, klass, error);
6514 HANDLE_FUNCTION_RETURN_OBJ (result);
6518 * mono_object_handle_isinst:
6519 * \param obj an object
6520 * \param klass a pointer to a class
6521 * \param error set on error
6522 * \returns \p obj if \p obj is derived from \p klass or NULL if it isn't.
6523 * On failure returns NULL and sets \p error.
6526 mono_object_handle_isinst (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
6531 mono_class_init (klass);
6533 if (mono_class_is_marshalbyref (klass) || mono_class_is_interface (klass)) {
6534 return mono_object_handle_isinst_mbyref (obj, klass, error);
6537 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6539 if (!MONO_HANDLE_IS_NULL (obj) && mono_class_is_assignable_from (klass, mono_handle_class (obj)))
6540 MONO_HANDLE_ASSIGN (result, obj);
6545 * mono_object_isinst_mbyref:
6548 mono_object_isinst_mbyref (MonoObject *obj_raw, MonoClass *klass)
6550 MONO_REQ_GC_UNSAFE_MODE;
6552 HANDLE_FUNCTION_ENTER ();
6554 MONO_HANDLE_DCL (MonoObject, obj);
6555 MonoObjectHandle result = mono_object_handle_isinst_mbyref (obj, klass, &error);
6556 mono_error_cleanup (&error); /* FIXME better API that doesn't swallow the error */
6557 HANDLE_FUNCTION_RETURN_OBJ (result);
6561 mono_object_handle_isinst_mbyref (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
6565 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6567 if (MONO_HANDLE_IS_NULL (obj))
6570 MonoVTable *vt = MONO_HANDLE_GETVAL (obj, vtable);
6572 if (mono_class_is_interface (klass)) {
6573 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
6574 MONO_HANDLE_ASSIGN (result, obj);
6578 /* casting an array one of the invariant interfaces that must act as such */
6579 if (klass->is_array_special_interface) {
6580 if (mono_class_is_assignable_from (klass, vt->klass)) {
6581 MONO_HANDLE_ASSIGN (result, obj);
6586 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
6587 else if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, mono_handle_class (obj))) {
6588 MONO_HANDLE_ASSIGN (result, obj);
6592 MonoClass *oklass = vt->klass;
6593 if (mono_class_is_transparent_proxy (oklass)){
6594 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), remote_class);
6595 oklass = remote_class->proxy_class;
6598 mono_class_setup_supertypes (klass);
6599 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass)) {
6600 MONO_HANDLE_ASSIGN (result, obj);
6604 #ifndef DISABLE_REMOTING
6605 if (mono_class_is_transparent_proxy (vt->klass))
6607 MonoBoolean custom_type_info = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), custom_type_info);
6608 if (!custom_type_info)
6610 MonoDomain *domain = mono_domain_get ();
6611 MonoObjectHandle rp = MONO_HANDLE_NEW (MonoObject, NULL);
6612 MONO_HANDLE_GET (rp, MONO_HANDLE_CAST (MonoTransparentProxy, obj), rp);
6613 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
6614 MonoMethod *im = NULL;
6617 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
6619 mono_error_set_not_supported (error, "Linked away.");
6622 im = mono_object_handle_get_virtual_method (rp, im, error);
6627 MonoReflectionTypeHandle reftype = mono_type_get_object_handle (domain, &klass->byval_arg, error);
6631 pa [0] = MONO_HANDLE_RAW (reftype);
6632 pa [1] = MONO_HANDLE_RAW (obj);
6633 MonoObject *res = mono_runtime_invoke_checked (im, MONO_HANDLE_RAW (rp), pa, error);
6637 if (*(MonoBoolean *) mono_object_unbox(res)) {
6638 /* Update the vtable of the remote type, so it can safely cast to this new type */
6639 mono_upgrade_remote_class (domain, obj, klass, error);
6642 MONO_HANDLE_ASSIGN (result, obj);
6645 #endif /* DISABLE_REMOTING */
6651 * mono_object_castclass_mbyref:
6652 * \param obj an object
6653 * \param klass a pointer to a class
6654 * \returns \p obj if \p obj is derived from \p klass, returns NULL otherwise.
6657 mono_object_castclass_mbyref (MonoObject *obj_raw, MonoClass *klass)
6659 MONO_REQ_GC_UNSAFE_MODE;
6660 HANDLE_FUNCTION_ENTER ();
6662 MONO_HANDLE_DCL (MonoObject, obj);
6663 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6664 if (MONO_HANDLE_IS_NULL (obj))
6666 MONO_HANDLE_ASSIGN (result, mono_object_handle_isinst_mbyref (obj, klass, &error));
6667 mono_error_cleanup (&error);
6669 HANDLE_FUNCTION_RETURN_OBJ (result);
6673 MonoDomain *orig_domain;
6679 str_lookup (MonoDomain *domain, gpointer user_data)
6681 MONO_REQ_GC_UNSAFE_MODE;
6683 LDStrInfo *info = (LDStrInfo *)user_data;
6684 if (info->res || domain == info->orig_domain)
6686 info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
6690 mono_string_get_pinned (MonoString *str, MonoError *error)
6692 MONO_REQ_GC_UNSAFE_MODE;
6696 /* We only need to make a pinned version of a string if this is a moving GC */
6697 if (!mono_gc_is_moving ())
6701 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
6702 news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
6704 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
6705 news->length = mono_string_length (str);
6707 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6713 mono_string_is_interned_lookup (MonoString *str, int insert, MonoError *error)
6715 MONO_REQ_GC_UNSAFE_MODE;
6717 MonoGHashTable *ldstr_table;
6718 MonoString *s, *res;
6723 domain = ((MonoObject *)str)->vtable->domain;
6724 ldstr_table = domain->ldstr_table;
6726 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6732 /* Allocate outside the lock */
6734 s = mono_string_get_pinned (str, error);
6735 return_val_if_nok (error, NULL);
6738 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6743 mono_g_hash_table_insert (ldstr_table, s, s);
6748 LDStrInfo ldstr_info;
6749 ldstr_info.orig_domain = domain;
6750 ldstr_info.ins = str;
6751 ldstr_info.res = NULL;
6753 mono_domain_foreach (str_lookup, &ldstr_info);
6754 if (ldstr_info.res) {
6756 * the string was already interned in some other domain:
6757 * intern it in the current one as well.
6759 mono_g_hash_table_insert (ldstr_table, str, str);
6769 * mono_string_is_interned:
6770 * \param o String to probe
6771 * \returns Whether the string has been interned.
6774 mono_string_is_interned (MonoString *o)
6777 MonoString *result = mono_string_is_interned_lookup (o, FALSE, &error);
6778 /* This function does not fail. */
6779 mono_error_assert_ok (&error);
6784 * mono_string_intern:
6785 * \param o String to intern
6786 * Interns the string passed.
6787 * \returns The interned string.
6790 mono_string_intern (MonoString *str)
6793 MonoString *result = mono_string_intern_checked (str, &error);
6794 mono_error_assert_ok (&error);
6799 * mono_string_intern_checked:
6800 * \param o String to intern
6801 * \param error set on error.
6802 * Interns the string passed.
6803 * \returns The interned string. On failure returns NULL and sets \p error
6806 mono_string_intern_checked (MonoString *str, MonoError *error)
6808 MONO_REQ_GC_UNSAFE_MODE;
6812 return mono_string_is_interned_lookup (str, TRUE, error);
6817 * \param domain the domain where the string will be used.
6818 * \param image a metadata context
6819 * \param idx index into the user string table.
6820 * Implementation for the \c ldstr opcode.
6821 * \returns a loaded string from the \p image / \p idx combination.
6824 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
6827 MonoString *result = mono_ldstr_checked (domain, image, idx, &error);
6828 mono_error_cleanup (&error);
6833 * mono_ldstr_checked:
6834 * \param domain the domain where the string will be used.
6835 * \param image a metadata context
6836 * \param idx index into the user string table.
6837 * \param error set on error.
6838 * Implementation for the \c ldstr opcode.
6839 * \returns A loaded string from the \p image / \p idx combination.
6840 * On failure returns NULL and sets \p error.
6843 mono_ldstr_checked (MonoDomain *domain, MonoImage *image, guint32 idx, MonoError *error)
6845 MONO_REQ_GC_UNSAFE_MODE;
6848 if (image->dynamic) {
6849 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL, error);
6852 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6853 return NULL; /*FIXME we should probably be raising an exception here*/
6854 MonoString *str = mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx), error);
6860 * mono_ldstr_metadata_sig
6861 * \param domain the domain for the string
6862 * \param sig the signature of a metadata string
6863 * \param error set on error
6864 * \returns a \c MonoString for a string stored in the metadata. On
6865 * failure returns NULL and sets \p error.
6868 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error)
6870 MONO_REQ_GC_UNSAFE_MODE;
6873 const char *str = sig;
6874 MonoString *o, *interned;
6877 len2 = mono_metadata_decode_blob_size (str, &str);
6880 o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, error);
6881 return_val_if_nok (error, NULL);
6882 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
6885 guint16 *p2 = (guint16*)mono_string_chars (o);
6886 for (i = 0; i < len2; ++i) {
6887 *p2 = GUINT16_FROM_LE (*p2);
6893 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6896 return interned; /* o will get garbage collected */
6898 o = mono_string_get_pinned (o, error);
6901 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6903 mono_g_hash_table_insert (domain->ldstr_table, o, o);
6915 * Same as mono_ldstr, but return a NULL terminated utf8 string instead
6919 mono_ldstr_utf8 (MonoImage *image, guint32 idx, MonoError *error)
6925 GError *gerror = NULL;
6929 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6930 return NULL; /*FIXME we should probably be raising an exception here*/
6931 str = mono_metadata_user_string (image, idx);
6933 len2 = mono_metadata_decode_blob_size (str, &str);
6936 as = g_utf16_to_utf8 ((guint16*)str, len2, NULL, &written, &gerror);
6938 mono_error_set_argument (error, "string", "%s", gerror->message);
6939 g_error_free (gerror);
6942 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6943 if (len2 > written) {
6944 /* allocate the total length and copy the part of the string that has been converted */
6945 char *as2 = (char *)g_malloc0 (len2);
6946 memcpy (as2, as, written);
6955 * mono_string_to_utf8:
6956 * \param s a \c System.String
6957 * \deprecated Use \c mono_string_to_utf8_checked to avoid having an exception arbitrarily raised.
6958 * \returns the UTF-8 representation for \p s.
6959 * The resulting buffer needs to be freed with \c mono_free().
6962 mono_string_to_utf8 (MonoString *s)
6964 MONO_REQ_GC_UNSAFE_MODE;
6967 char *result = mono_string_to_utf8_checked (s, &error);
6969 if (!is_ok (&error)) {
6970 mono_error_cleanup (&error);
6977 * mono_string_to_utf8_checked:
6978 * \param s a \c System.String
6979 * \param error a \c MonoError.
6980 * Converts a \c MonoString to its UTF-8 representation. May fail; check
6981 * \p error to determine whether the conversion was successful.
6982 * The resulting buffer should be freed with \c mono_free().
6985 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
6987 MONO_REQ_GC_UNSAFE_MODE;
6991 GError *gerror = NULL;
6999 return g_strdup ("");
7001 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
7003 mono_error_set_argument (error, "string", "%s", gerror->message);
7004 g_error_free (gerror);
7007 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
7008 if (s->length > written) {
7009 /* allocate the total length and copy the part of the string that has been converted */
7010 char *as2 = (char *)g_malloc0 (s->length);
7011 memcpy (as2, as, written);
7020 mono_string_handle_to_utf8 (MonoStringHandle s, MonoError *error)
7022 return mono_string_to_utf8_checked (MONO_HANDLE_RAW (s), error);
7026 * mono_string_to_utf8_ignore:
7027 * \param s a MonoString
7028 * Converts a \c MonoString to its UTF-8 representation. Will ignore
7029 * invalid surrogate pairs.
7030 * The resulting buffer should be freed with \c mono_free().
7033 mono_string_to_utf8_ignore (MonoString *s)
7035 MONO_REQ_GC_UNSAFE_MODE;
7044 return g_strdup ("");
7046 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
7048 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
7049 if (s->length > written) {
7050 /* allocate the total length and copy the part of the string that has been converted */
7051 char *as2 = (char *)g_malloc0 (s->length);
7052 memcpy (as2, as, written);
7061 * mono_string_to_utf8_image_ignore:
7062 * \param s a \c System.String
7063 * Same as \c mono_string_to_utf8_ignore, but allocate the string from the image mempool.
7066 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
7068 MONO_REQ_GC_UNSAFE_MODE;
7070 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
7074 * mono_string_to_utf8_mp_ignore:
7075 * \param s a \c System.String
7076 * Same as \c mono_string_to_utf8_ignore, but allocate the string from a mempool.
7079 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
7081 MONO_REQ_GC_UNSAFE_MODE;
7083 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
7088 * mono_string_to_utf16:
7089 * \param s a \c MonoString
7090 * \returns a null-terminated array of the UTF-16 chars
7091 * contained in \p s. The result must be freed with \c g_free().
7092 * This is a temporary helper until our string implementation
7093 * is reworked to always include the null-terminating char.
7096 mono_string_to_utf16 (MonoString *s)
7098 MONO_REQ_GC_UNSAFE_MODE;
7105 as = (char *)g_malloc ((s->length * 2) + 2);
7106 as [(s->length * 2)] = '\0';
7107 as [(s->length * 2) + 1] = '\0';
7110 return (gunichar2 *)(as);
7113 memcpy (as, mono_string_chars(s), s->length * 2);
7114 return (gunichar2 *)(as);
7118 * mono_string_to_utf32:
7119 * \param s a \c MonoString
7120 * \returns a null-terminated array of the UTF-32 (UCS-4) chars
7121 * contained in \p s. The result must be freed with \c g_free().
7124 mono_string_to_utf32 (MonoString *s)
7126 MONO_REQ_GC_UNSAFE_MODE;
7128 mono_unichar4 *utf32_output = NULL;
7129 GError *error = NULL;
7130 glong items_written;
7135 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
7138 g_error_free (error);
7140 return utf32_output;
7144 * mono_string_from_utf16:
7145 * \param data the UTF-16 string (LPWSTR) to convert
7146 * Converts a NULL-terminated UTF-16 string (LPWSTR) to a \c MonoString.
7147 * \returns a \c MonoString.
7150 mono_string_from_utf16 (gunichar2 *data)
7153 MonoString *result = mono_string_from_utf16_checked (data, &error);
7154 mono_error_cleanup (&error);
7159 * mono_string_from_utf16_checked:
7160 * \param data the UTF-16 string (LPWSTR) to convert
7161 * \param error set on error
7162 * Converts a NULL-terminated UTF-16 string (LPWSTR) to a \c MonoString.
7163 * \returns a \c MonoString. On failure sets \p error and returns NULL.
7166 mono_string_from_utf16_checked (gunichar2 *data, MonoError *error)
7169 MONO_REQ_GC_UNSAFE_MODE;
7172 MonoDomain *domain = mono_domain_get ();
7178 while (data [len]) len++;
7180 return mono_string_new_utf16_checked (domain, data, len, error);
7184 * mono_string_from_utf32:
7185 * \param data the UTF-32 string (LPWSTR) to convert
7186 * Converts a UTF-32 (UCS-4) string to a \c MonoString.
7187 * \returns a \c MonoString.
7190 mono_string_from_utf32 (mono_unichar4 *data)
7193 MonoString *result = mono_string_from_utf32_checked (data, &error);
7194 mono_error_cleanup (&error);
7199 * mono_string_from_utf32_checked:
7200 * \param data the UTF-32 string (LPWSTR) to convert
7201 * \param error set on error
7202 * Converts a UTF-32 (UCS-4) string to a \c MonoString.
7203 * \returns a \c MonoString. On failure returns NULL and sets \p error.
7206 mono_string_from_utf32_checked (mono_unichar4 *data, MonoError *error)
7208 MONO_REQ_GC_UNSAFE_MODE;
7211 MonoString* result = NULL;
7212 mono_unichar2 *utf16_output = NULL;
7213 GError *gerror = NULL;
7214 glong items_written;
7220 while (data [len]) len++;
7222 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &gerror);
7225 g_error_free (gerror);
7227 result = mono_string_from_utf16_checked (utf16_output, error);
7228 g_free (utf16_output);
7233 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
7235 MONO_REQ_GC_UNSAFE_MODE;
7242 r = mono_string_to_utf8_ignore (s);
7244 r = mono_string_to_utf8_checked (s, error);
7245 if (!mono_error_ok (error))
7252 len = strlen (r) + 1;
7254 mp_s = (char *)mono_mempool_alloc (mp, len);
7256 mp_s = (char *)mono_image_alloc (image, len);
7258 memcpy (mp_s, r, len);
7266 * mono_string_to_utf8_image:
7267 * \param s a \c System.String
7268 * Same as \c mono_string_to_utf8, but allocate the string from the image mempool.
7271 mono_string_to_utf8_image (MonoImage *image, MonoStringHandle s, MonoError *error)
7273 MONO_REQ_GC_UNSAFE_MODE;
7275 return mono_string_to_utf8_internal (NULL, image, MONO_HANDLE_RAW (s), FALSE, error); /* FIXME pin the string */
7279 * mono_string_to_utf8_mp:
7280 * \param s a \c System.String
7281 * Same as \c mono_string_to_utf8, but allocate the string from a mempool.
7284 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
7286 MONO_REQ_GC_UNSAFE_MODE;
7288 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
7292 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
7295 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
7297 eh_callbacks = *cbs;
7300 MonoRuntimeExceptionHandlingCallbacks *
7301 mono_get_eh_callbacks (void)
7303 return &eh_callbacks;
7307 * mono_raise_exception:
7308 * \param ex exception object
7309 * Signal the runtime that the exception \p ex has been raised in unmanaged code.
7312 mono_raise_exception (MonoException *ex)
7314 MONO_REQ_GC_UNSAFE_MODE;
7317 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
7318 * that will cause gcc to omit the function epilog, causing problems when
7319 * the JIT tries to walk the stack, since the return address on the stack
7320 * will point into the next function in the executable, not this one.
7322 eh_callbacks.mono_raise_exception (ex);
7326 * mono_raise_exception:
7327 * \param ex exception object
7328 * Signal the runtime that the exception \p ex has been raised in unmanaged code.
7331 mono_reraise_exception (MonoException *ex)
7333 MONO_REQ_GC_UNSAFE_MODE;
7336 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
7337 * that will cause gcc to omit the function epilog, causing problems when
7338 * the JIT tries to walk the stack, since the return address on the stack
7339 * will point into the next function in the executable, not this one.
7341 eh_callbacks.mono_reraise_exception (ex);
7345 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
7347 MONO_REQ_GC_UNSAFE_MODE;
7349 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
7353 * mono_wait_handle_new:
7354 * \param domain Domain where the object will be created
7355 * \param handle Handle for the wait handle
7356 * \param error set on error.
7357 * \returns A new \c MonoWaitHandle created in the given domain for the
7358 * given handle. On failure returns NULL and sets \p error.
7361 mono_wait_handle_new (MonoDomain *domain, HANDLE handle, MonoError *error)
7363 MONO_REQ_GC_UNSAFE_MODE;
7365 MonoWaitHandle *res;
7366 gpointer params [1];
7367 static MonoMethod *handle_set;
7370 res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, error);
7371 return_val_if_nok (error, NULL);
7373 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
7375 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
7377 params [0] = &handle;
7379 mono_runtime_invoke_checked (handle_set, res, params, error);
7384 mono_wait_handle_get_handle (MonoWaitHandle *handle)
7386 MONO_REQ_GC_UNSAFE_MODE;
7388 static MonoClassField *f_safe_handle = NULL;
7391 if (!f_safe_handle) {
7392 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safeWaitHandle");
7393 g_assert (f_safe_handle);
7396 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
7402 mono_runtime_capture_context (MonoDomain *domain, MonoError *error)
7404 MONO_REQ_GC_UNSAFE_MODE;
7406 RuntimeInvokeFunction runtime_invoke;
7410 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
7411 MonoMethod *method = mono_get_context_capture_method ();
7412 MonoMethod *wrapper;
7415 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
7416 domain->capture_context_runtime_invoke = mono_compile_method_checked (wrapper, error);
7417 return_val_if_nok (error, NULL);
7418 domain->capture_context_method = mono_compile_method_checked (method, error);
7419 return_val_if_nok (error, NULL);
7422 runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
7424 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
7427 * mono_async_result_new:
7428 * \param domain domain where the object will be created.
7429 * \param handle wait handle.
7430 * \param state state to pass to AsyncResult
7431 * \param data C closure data.
7432 * \param error set on error.
7433 * Creates a new MonoAsyncResult (\c AsyncResult C# class) in the given domain.
7434 * If the handle is not null, the handle is initialized to a \c MonoWaitHandle.
7435 * On failure returns NULL and sets \p error.
7438 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data, MonoError *error)
7440 MONO_REQ_GC_UNSAFE_MODE;
7443 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, error);
7444 return_val_if_nok (error, NULL);
7445 MonoObject *context = mono_runtime_capture_context (domain, error);
7446 return_val_if_nok (error, NULL);
7447 /* we must capture the execution context from the original thread */
7449 MONO_OBJECT_SETREF (res, execution_context, context);
7450 /* note: result may be null if the flow is suppressed */
7453 res->data = (void **)data;
7454 MONO_OBJECT_SETREF (res, object_data, object_data);
7455 MONO_OBJECT_SETREF (res, async_state, state);
7456 MonoWaitHandle *wait_handle = mono_wait_handle_new (domain, handle, error);
7457 return_val_if_nok (error, NULL);
7459 MONO_OBJECT_SETREF (res, handle, (MonoObject *) wait_handle);
7461 res->sync_completed = FALSE;
7462 res->completed = FALSE;
7468 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
7470 MONO_REQ_GC_UNSAFE_MODE;
7477 g_assert (ares->async_delegate);
7479 ac = (MonoAsyncCall*) ares->object_data;
7481 res = mono_runtime_delegate_invoke_checked (ares->async_delegate, (void**) &ares->async_state, &error);
7482 if (mono_error_set_pending_exception (&error))
7485 gpointer wait_event = NULL;
7487 ac->msg->exc = NULL;
7489 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args, &error);
7491 /* The exit side of the invoke must not be aborted as it would leave the runtime in an undefined state */
7492 mono_threads_begin_abort_protected_block ();
7494 if (!ac->msg->exc) {
7495 MonoException *ex = mono_error_convert_to_exception (&error);
7496 ac->msg->exc = (MonoObject *)ex;
7498 mono_error_cleanup (&error);
7501 MONO_OBJECT_SETREF (ac, res, res);
7503 mono_monitor_enter ((MonoObject*) ares);
7504 ares->completed = 1;
7506 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
7507 mono_monitor_exit ((MonoObject*) ares);
7509 if (wait_event != NULL)
7510 mono_w32event_set (wait_event);
7512 error_init (&error); //the else branch would leave it in an undefined state
7514 mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
7516 mono_threads_end_abort_protected_block ();
7518 if (mono_error_set_pending_exception (&error))
7526 mono_message_init (MonoDomain *domain,
7527 MonoMethodMessage *this_obj,
7528 MonoReflectionMethod *method,
7529 MonoArray *out_args,
7532 MONO_REQ_GC_UNSAFE_MODE;
7534 static MonoMethod *init_message_method = NULL;
7536 if (!init_message_method) {
7537 init_message_method = mono_class_get_method_from_name (mono_defaults.mono_method_message_class, "InitMessage", 2);
7538 g_assert (init_message_method != NULL);
7542 /* FIXME set domain instead? */
7543 g_assert (domain == mono_domain_get ());
7550 mono_runtime_invoke_checked (init_message_method, this_obj, args, error);
7551 return is_ok (error);
7554 #ifndef DISABLE_REMOTING
7556 * mono_remoting_invoke:
7557 * \param real_proxy pointer to a \c RealProxy object
7558 * \param msg The \c MonoMethodMessage to execute
7559 * \param exc used to store exceptions
7560 * \param out_args used to store output arguments
7561 * This is used to call \c RealProxy::Invoke(). \c RealProxy::Invoke() returns an
7562 * \c IMessage interface and it is not trivial to extract results from there. So
7563 * we call an helper method \c PrivateInvoke instead of calling
7564 * \c RealProxy::Invoke() directly.
7565 * \returns the result object.
7568 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, MonoObject **exc, MonoArray **out_args, MonoError *error)
7570 MONO_REQ_GC_UNSAFE_MODE;
7573 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
7580 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
7583 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
7585 mono_error_set_not_supported (error, "Linked away.");
7588 real_proxy->vtable->domain->private_invoke_method = im;
7591 pa [0] = real_proxy;
7596 o = mono_runtime_try_invoke (im, NULL, pa, exc, error);
7597 return_val_if_nok (error, NULL);
7604 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
7605 MonoObject **exc, MonoArray **out_args, MonoError *error)
7607 MONO_REQ_GC_UNSAFE_MODE;
7609 static MonoClass *object_array_klass;
7614 MonoMethodSignature *sig;
7616 int i, j, outarg_count = 0;
7618 #ifndef DISABLE_REMOTING
7619 if (target && mono_object_is_transparent_proxy (target)) {
7620 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
7621 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7622 target = tp->rp->unwrapped_server;
7624 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args, error);
7629 domain = mono_domain_get ();
7630 method = msg->method->method;
7631 sig = mono_method_signature (method);
7633 for (i = 0; i < sig->param_count; i++) {
7634 if (sig->params [i]->byref)
7638 if (!object_array_klass) {
7641 klass = mono_array_class_get (mono_defaults.object_class, 1);
7644 mono_memory_barrier ();
7645 object_array_klass = klass;
7648 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, error);
7649 return_val_if_nok (error, NULL);
7651 mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
7654 MonoObject *ret = mono_runtime_try_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc, error);
7655 return_val_if_nok (error, NULL);
7657 for (i = 0, j = 0; i < sig->param_count; i++) {
7658 if (sig->params [i]->byref) {
7660 arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
7661 mono_array_setref (*out_args, j, arg);
7670 * prepare_to_string_method:
7672 * @target: Set to @obj or unboxed value if a valuetype
7674 * Returns: the ToString override for @obj. If @obj is a valuetype, @target is unboxed otherwise it's @obj.
7677 prepare_to_string_method (MonoObject *obj, void **target)
7679 MONO_REQ_GC_UNSAFE_MODE;
7681 static MonoMethod *to_string = NULL;
7689 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
7691 method = mono_object_get_virtual_method (obj, to_string);
7693 // Unbox value type if needed
7694 if (mono_class_is_valuetype (mono_method_get_class (method))) {
7695 *target = mono_object_unbox (obj);
7701 * mono_object_to_string:
7702 * \param obj The object
7703 * \param exc Any exception thrown by \c ToString. May be NULL.
7704 * \returns the result of calling \c ToString on an object.
7707 mono_object_to_string (MonoObject *obj, MonoObject **exc)
7710 MonoString *s = NULL;
7712 MonoMethod *method = prepare_to_string_method (obj, &target);
7714 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
7715 if (*exc == NULL && !mono_error_ok (&error))
7716 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
7718 mono_error_cleanup (&error);
7720 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
7721 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
7728 * mono_object_to_string_checked:
7729 * \param obj The object
7730 * \param error Set on error.
7731 * \returns the result of calling \c ToString() on an object. If the
7732 * method cannot be invoked or if it raises an exception, sets \p error
7736 mono_object_to_string_checked (MonoObject *obj, MonoError *error)
7740 MonoMethod *method = prepare_to_string_method (obj, &target);
7741 return (MonoString*) mono_runtime_invoke_checked (method, target, NULL, error);
7745 * mono_object_try_to_string:
7746 * \param obj The object
7747 * \param exc Any exception thrown by \c ToString(). Must not be NULL.
7748 * \param error Set if method cannot be invoked.
7749 * \returns the result of calling \c ToString() on an object. If the
7750 * method cannot be invoked sets \p error, if it raises an exception sets \p exc,
7754 mono_object_try_to_string (MonoObject *obj, MonoObject **exc, MonoError *error)
7759 MonoMethod *method = prepare_to_string_method (obj, &target);
7760 return (MonoString*) mono_runtime_try_invoke (method, target, NULL, exc, error);
7766 get_native_backtrace (MonoException *exc_raw)
7768 HANDLE_FUNCTION_ENTER ();
7769 MONO_HANDLE_DCL(MonoException, exc);
7770 char * trace = mono_exception_handle_get_native_backtrace (exc);
7771 HANDLE_FUNCTION_RETURN_VAL (trace);
7775 * mono_print_unhandled_exception:
7776 * \param exc The exception
7777 * Prints the unhandled exception.
7780 mono_print_unhandled_exception (MonoObject *exc)
7782 MONO_REQ_GC_UNSAFE_MODE;
7785 char *message = (char*)"";
7786 gboolean free_message = FALSE;
7789 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
7790 message = g_strdup ("OutOfMemoryException");
7791 free_message = TRUE;
7792 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
7793 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
7794 free_message = TRUE;
7797 if (((MonoException*)exc)->native_trace_ips) {
7798 message = get_native_backtrace ((MonoException*)exc);
7799 free_message = TRUE;
7801 MonoObject *other_exc = NULL;
7802 str = mono_object_try_to_string (exc, &other_exc, &error);
7803 if (other_exc == NULL && !is_ok (&error))
7804 other_exc = (MonoObject*)mono_error_convert_to_exception (&error);
7806 mono_error_cleanup (&error);
7808 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
7809 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
7811 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
7812 original_backtrace, nested_backtrace);
7814 g_free (original_backtrace);
7815 g_free (nested_backtrace);
7816 free_message = TRUE;
7818 message = mono_string_to_utf8_checked (str, &error);
7819 if (!mono_error_ok (&error)) {
7820 mono_error_cleanup (&error);
7821 message = (char *) "";
7823 free_message = TRUE;
7830 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
7831 * exc->vtable->klass->name, message);
7833 g_printerr ("\nUnhandled Exception:\n%s\n", message);
7840 * mono_delegate_ctor_with_method:
7841 * \param this pointer to an uninitialized delegate object
7842 * \param target target object
7843 * \param addr pointer to native code
7844 * \param method method
7845 * \param error set on error.
7846 * Initialize a delegate and sets a specific method, not the one
7847 * associated with \p addr. This is useful when sharing generic code.
7848 * In that case \p addr will most probably not be associated with the
7849 * correct instantiation of the method.
7850 * On failure returns FALSE and sets \p error.
7853 mono_delegate_ctor_with_method (MonoObjectHandle this_obj, MonoObjectHandle target, gpointer addr, MonoMethod *method, MonoError *error)
7855 MONO_REQ_GC_UNSAFE_MODE;
7858 MonoDelegateHandle delegate = MONO_HANDLE_CAST (MonoDelegate, this_obj);
7860 g_assert (!MONO_HANDLE_IS_NULL (this_obj));
7863 MonoClass *klass = mono_handle_class (this_obj);
7864 g_assert (mono_class_has_parent (klass, mono_defaults.multicastdelegate_class));
7867 MONO_HANDLE_SETVAL (delegate, method, MonoMethod*, method);
7869 mono_stats.delegate_creations++;
7871 #ifndef DISABLE_REMOTING
7872 if (!MONO_HANDLE_IS_NULL (target) && mono_class_is_transparent_proxy (mono_handle_class (target))) {
7874 method = mono_marshal_get_remoting_invoke (method);
7875 #ifdef ENABLE_INTERPRETER
7876 //g_error ("need RuntimeMethod in method_ptr when using interpreter");
7878 MONO_HANDLE_SETVAL (delegate, method_ptr, gpointer, mono_compile_method_checked (method, error));
7879 return_val_if_nok (error, FALSE);
7880 MONO_HANDLE_SET (delegate, target, target);
7884 MONO_HANDLE_SETVAL (delegate, method_ptr, gpointer, addr);
7885 MONO_HANDLE_SET (delegate, target, target);
7888 MONO_HANDLE_SETVAL (delegate, invoke_impl, gpointer, callbacks.create_delegate_trampoline (MONO_HANDLE_DOMAIN (delegate), mono_handle_class (delegate)));
7889 if (callbacks.init_delegate)
7890 callbacks.init_delegate (MONO_HANDLE_RAW (delegate)); /* FIXME: update init_delegate callback to take a MonoDelegateHandle */
7895 * mono_delegate_ctor:
7896 * \param this pointer to an uninitialized delegate object
7897 * \param target target object
7898 * \param addr pointer to native code
7899 * \param error set on error.
7900 * This is used to initialize a delegate.
7901 * On failure returns FALSE and sets \p error.
7904 mono_delegate_ctor (MonoObjectHandle this_obj, MonoObjectHandle target, gpointer addr, MonoError *error)
7906 MONO_REQ_GC_UNSAFE_MODE;
7909 MonoDomain *domain = mono_domain_get ();
7911 MonoMethod *method = NULL;
7915 ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
7917 if (!ji && domain != mono_get_root_domain ())
7918 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
7920 method = mono_jit_info_get_method (ji);
7921 g_assert (!mono_class_is_gtd (method->klass));
7924 return mono_delegate_ctor_with_method (this_obj, target, addr, method, error);
7928 * mono_method_call_message_new:
7929 * \param method method to encapsulate
7930 * \param params parameters to the method
7931 * \param invoke optional, delegate invoke.
7932 * \param cb async callback delegate.
7933 * \param state state passed to the async callback.
7934 * \param error set on error.
7935 * Translates arguments pointers into a \c MonoMethodMessage.
7936 * On failure returns NULL and sets \p error.
7939 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
7940 MonoDelegate **cb, MonoObject **state, MonoError *error)
7942 MONO_REQ_GC_UNSAFE_MODE;
7946 MonoDomain *domain = mono_domain_get ();
7947 MonoMethodSignature *sig = mono_method_signature (method);
7948 MonoMethodMessage *msg;
7951 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
7952 return_val_if_nok (error, NULL);
7955 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, error);
7956 return_val_if_nok (error, NULL);
7957 mono_message_init (domain, msg, rm, NULL, error);
7958 return_val_if_nok (error, NULL);
7959 count = sig->param_count - 2;
7961 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
7962 return_val_if_nok (error, NULL);
7963 mono_message_init (domain, msg, rm, NULL, error);
7964 return_val_if_nok (error, NULL);
7965 count = sig->param_count;
7968 for (i = 0; i < count; i++) {
7973 if (sig->params [i]->byref)
7974 vpos = *((gpointer *)params [i]);
7978 klass = mono_class_from_mono_type (sig->params [i]);
7980 if (klass->valuetype) {
7981 arg = mono_value_box_checked (domain, klass, vpos, error);
7982 return_val_if_nok (error, NULL);
7984 arg = *((MonoObject **)vpos);
7986 mono_array_setref (msg->args, i, arg);
7989 if (cb != NULL && state != NULL) {
7990 *cb = *((MonoDelegate **)params [i]);
7992 *state = *((MonoObject **)params [i]);
7999 * mono_method_return_message_restore:
8001 * Restore results from message based processing back to arguments pointers
8004 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args, MonoError *error)
8006 MONO_REQ_GC_UNSAFE_MODE;
8010 MonoMethodSignature *sig = mono_method_signature (method);
8011 int i, j, type, size, out_len;
8013 if (out_args == NULL)
8015 out_len = mono_array_length (out_args);
8019 for (i = 0, j = 0; i < sig->param_count; i++) {
8020 MonoType *pt = sig->params [i];
8025 mono_error_set_execution_engine (error, "The proxy call returned an incorrect number of output arguments");
8029 arg = (char *)mono_array_get (out_args, gpointer, j);
8032 g_assert (type != MONO_TYPE_VOID);
8034 if (MONO_TYPE_IS_REFERENCE (pt)) {
8035 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
8038 MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
8039 size = mono_class_value_size (klass, NULL);
8040 if (klass->has_references)
8041 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
8043 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
8045 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
8046 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
8055 #ifndef DISABLE_REMOTING
8058 * mono_load_remote_field:
8059 * \param this pointer to an object
8060 * \param klass klass of the object containing \p field
8061 * \param field the field to load
8062 * \param res a storage to store the result
8063 * This method is called by the runtime on attempts to load fields of
8064 * transparent proxy objects. \p this points to such TP, \p klass is the class of
8065 * the object containing \p field. \p res is a storage location which can be
8066 * used to store the result.
8067 * \returns an address pointing to the value of field.
8070 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
8073 gpointer result = mono_load_remote_field_checked (this_obj, klass, field, res, &error);
8074 mono_error_cleanup (&error);
8079 * mono_load_remote_field_checked:
8080 * \param this pointer to an object
8081 * \param klass klass of the object containing \p field
8082 * \param field the field to load
8083 * \param res a storage to store the result
8084 * \param error set on error
8085 * This method is called by the runtime on attempts to load fields of
8086 * transparent proxy objects. \p this points to such TP, \p klass is the class of
8087 * the object containing \p field. \p res is a storage location which can be
8088 * used to store the result.
8089 * \returns an address pointing to the value of field. On failure returns NULL and sets \p error.
8092 mono_load_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res, MonoError *error)
8094 MONO_REQ_GC_UNSAFE_MODE;
8096 static MonoMethod *getter = NULL;
8100 MonoDomain *domain = mono_domain_get ();
8101 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8102 MonoClass *field_class;
8103 MonoMethodMessage *msg;
8104 MonoArray *out_args;
8108 g_assert (mono_object_is_transparent_proxy (this_obj));
8109 g_assert (res != NULL);
8111 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8112 mono_field_get_value (tp->rp->unwrapped_server, field, res);
8117 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
8119 mono_error_set_not_supported (error, "Linked away.");
8124 field_class = mono_class_from_mono_type (field->type);
8126 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8127 return_val_if_nok (error, NULL);
8128 out_args = mono_array_new_checked (domain, mono_defaults.object_class, 1, error);
8129 return_val_if_nok (error, NULL);
8130 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, error);
8131 return_val_if_nok (error, NULL);
8132 mono_message_init (domain, msg, rm, out_args, error);
8133 return_val_if_nok (error, NULL);
8135 full_name = mono_type_get_full_name (klass);
8136 MonoString *full_name_str = mono_string_new_checked (domain, full_name, error);
8138 return_val_if_nok (error, NULL);
8139 mono_array_setref (msg->args, 0, full_name_str);
8140 MonoString *field_name = mono_string_new_checked (domain, mono_field_get_name (field), error);
8141 return_val_if_nok (error, NULL);
8142 mono_array_setref (msg->args, 1, field_name);
8144 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8145 return_val_if_nok (error, NULL);
8148 mono_error_set_exception_instance (error, (MonoException *)exc);
8152 if (mono_array_length (out_args) == 0)
8155 mono_gc_wbarrier_generic_store (res, mono_array_get (out_args, MonoObject *, 0));
8157 if (field_class->valuetype) {
8158 return ((char *)*res) + sizeof (MonoObject);
8164 * mono_load_remote_field_new:
8168 * Missing documentation.
8171 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
8175 MonoObject *result = mono_load_remote_field_new_checked (this_obj, klass, field, &error);
8176 mono_error_cleanup (&error);
8181 * mono_load_remote_field_new_checked:
8182 * \param this pointer to an object
8183 * \param klass klass of the object containing \p field
8184 * \param field the field to load
8185 * \param error set on error.
8186 * This method is called by the runtime on attempts to load fields of
8187 * transparent proxy objects. \p this points to such TP, \p klass is the class of
8188 * the object containing \p field.
8189 * \returns a freshly allocated object containing the value of the field. On failure returns NULL and sets \p error.
8192 mono_load_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoError *error)
8194 MONO_REQ_GC_UNSAFE_MODE;
8198 static MonoMethod *tp_load = NULL;
8200 g_assert (mono_object_is_transparent_proxy (this_obj));
8203 tp_load = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "LoadRemoteFieldNew", -1);
8205 mono_error_set_not_supported (error, "Linked away.");
8210 /* MonoType *type = mono_class_get_type (klass); */
8216 return mono_runtime_invoke_checked (tp_load, this_obj, args, error);
8220 * mono_store_remote_field:
8221 * \param this_obj pointer to an object
8222 * \param klass klass of the object containing \p field
8223 * \param field the field to load
8224 * \param val the value/object to store
8225 * This method is called by the runtime on attempts to store fields of
8226 * transparent proxy objects. \p this_obj points to such TP, \p klass is the class of
8227 * the object containing \p field. \p val is the new value to store in \p field.
8230 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
8233 (void) mono_store_remote_field_checked (this_obj, klass, field, val, &error);
8234 mono_error_cleanup (&error);
8238 * mono_store_remote_field_checked:
8239 * \param this_obj pointer to an object
8240 * \param klass klass of the object containing \p field
8241 * \param field the field to load
8242 * \param val the value/object to store
8243 * \param error set on error
8244 * This method is called by the runtime on attempts to store fields of
8245 * transparent proxy objects. \p this_obj points to such TP, \p klass is the class of
8246 * the object containing \p field. \p val is the new value to store in \p field.
8247 * \returns on success returns TRUE, on failure returns FALSE and sets \p error.
8250 mono_store_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val, MonoError *error)
8253 MONO_REQ_GC_UNSAFE_MODE;
8257 MonoDomain *domain = mono_domain_get ();
8258 MonoClass *field_class;
8261 g_assert (mono_object_is_transparent_proxy (this_obj));
8263 field_class = mono_class_from_mono_type (field->type);
8265 if (field_class->valuetype) {
8266 arg = mono_value_box_checked (domain, field_class, val, error);
8267 return_val_if_nok (error, FALSE);
8269 arg = *((MonoObject**)val);
8272 return mono_store_remote_field_new_checked (this_obj, klass, field, arg, error);
8276 * mono_store_remote_field_new:
8281 * Missing documentation
8284 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
8287 (void) mono_store_remote_field_new_checked (this_obj, klass, field, arg, &error);
8288 mono_error_cleanup (&error);
8292 * mono_store_remote_field_new_checked:
8298 * Missing documentation
8301 mono_store_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg, MonoError *error)
8303 MONO_REQ_GC_UNSAFE_MODE;
8305 static MonoMethod *tp_store = NULL;
8309 g_assert (mono_object_is_transparent_proxy (this_obj));
8312 tp_store = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "StoreRemoteField", -1);
8314 mono_error_set_not_supported (error, "Linked away.");
8324 mono_runtime_invoke_checked (tp_store, this_obj, args, error);
8325 return is_ok (error);
8330 * mono_create_ftnptr:
8332 * Given a function address, create a function descriptor for it.
8333 * This is only needed on some platforms.
8336 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
8338 return callbacks.create_ftnptr (domain, addr);
8342 * mono_get_addr_from_ftnptr:
8344 * Given a pointer to a function descriptor, return the function address.
8345 * This is only needed on some platforms.
8348 mono_get_addr_from_ftnptr (gpointer descr)
8350 return callbacks.get_addr_from_ftnptr (descr);
8354 * mono_string_chars:
8355 * \param s a \c MonoString
8356 * \returns a pointer to the UTF-16 characters stored in the \c MonoString
8359 mono_string_chars (MonoString *s)
8361 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
8367 * mono_string_length:
8368 * \param s MonoString
8369 * \returns the length in characters of the string
8372 mono_string_length (MonoString *s)
8374 MONO_REQ_GC_UNSAFE_MODE;
8380 * mono_string_handle_length:
8381 * \param s \c MonoString
8382 * \returns the length in characters of the string
8385 mono_string_handle_length (MonoStringHandle s)
8387 MONO_REQ_GC_UNSAFE_MODE;
8389 return MONO_HANDLE_GETVAL (s, length);
8394 * mono_array_length:
8395 * \param array a \c MonoArray*
8396 * \returns the total number of elements in the array. This works for
8397 * both vectors and multidimensional arrays.
8400 mono_array_length (MonoArray *array)
8402 MONO_REQ_GC_UNSAFE_MODE;
8404 return array->max_length;
8408 * mono_array_addr_with_size:
8409 * \param array a \c MonoArray*
8410 * \param size size of the array elements
8411 * \param idx index into the array
8412 * Use this function to obtain the address for the \p idx item on the
8413 * \p array containing elements of size \p size.
8415 * This method performs no bounds checking or type checking.
8416 * \returns the address of the \p idx element in the array.
8419 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
8421 MONO_REQ_GC_UNSAFE_MODE;
8423 return ((char*)(array)->vector) + size * idx;
8428 mono_glist_to_array (GList *list, MonoClass *eclass, MonoError *error)
8430 MonoDomain *domain = mono_domain_get ();
8438 len = g_list_length (list);
8439 res = mono_array_new_checked (domain, eclass, len, error);
8440 return_val_if_nok (error, NULL);
8442 for (i = 0; list; list = list->next, i++)
8443 mono_array_set (res, gpointer, i, list->data);
8450 * The following section is purely to declare prototypes and
8451 * document the API, as these C files are processed by our
8457 * \param array array to alter
8458 * \param element_type A C type name, this macro will use the sizeof(type) to determine the element size
8459 * \param index index into the array
8460 * \param value value to set
8461 * Value Type version: This sets the \p index's element of the \p array
8462 * with elements of size sizeof(type) to the provided \p value.
8464 * This macro does not attempt to perform type checking or bounds checking.
8466 * Use this to set value types in a \c MonoArray.
8468 void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
8473 * mono_array_setref:
8474 * \param array array to alter
8475 * \param index index into the array
8476 * \param value value to set
8477 * Reference Type version. This sets the \p index's element of the
8478 * \p array with elements of size sizeof(type) to the provided \p value.
8480 * This macro does not attempt to perform type checking or bounds checking.
8482 * Use this to reference types in a \c MonoArray.
8484 void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
8490 * \param array array on which to operate on
8491 * \param element_type C element type (example: \c MonoString*, \c int, \c MonoObject*)
8492 * \param index index into the array
8494 * Use this macro to retrieve the \p index element of an \p array and
8495 * extract the value assuming that the elements of the array match
8496 * the provided type value.
8498 * This method can be used with both arrays holding value types and
8499 * reference types. For reference types, the \p type parameter should
8500 * be a \c MonoObject* or any subclass of it, like \c MonoString*.
8502 * This macro does not attempt to perform type checking or bounds checking.
8504 * \returns The element at the \p index position in the \p array.
8506 Type mono_array_get (MonoArray *array, Type element_type, uintptr_t index)