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);
245 mono_type_initialization_cleanup (void)
248 /* This is causing race conditions with
249 * mono_release_type_locks
251 mono_coop_mutex_destroy (&type_initialization_section);
252 g_hash_table_destroy (type_initialization_hash);
253 type_initialization_hash = NULL;
255 mono_os_mutex_destroy (&ldstr_section);
256 g_hash_table_destroy (blocked_thread_hash);
257 blocked_thread_hash = NULL;
263 * get_type_init_exception_for_vtable:
265 * Return the stored type initialization exception for VTABLE.
267 static MonoException*
268 get_type_init_exception_for_vtable (MonoVTable *vtable)
270 MONO_REQ_GC_UNSAFE_MODE;
273 MonoDomain *domain = vtable->domain;
274 MonoClass *klass = vtable->klass;
278 if (!vtable->init_failed)
279 g_error ("Trying to get the init exception for a non-failed vtable of class %s", mono_type_get_full_name (klass));
282 * If the initializing thread was rudely aborted, the exception is not stored
286 mono_domain_lock (domain);
287 if (domain->type_init_exception_hash)
288 ex = (MonoException *)mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
289 mono_domain_unlock (domain);
292 if (klass->name_space && *klass->name_space)
293 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
295 full_name = g_strdup (klass->name);
296 ex = mono_get_exception_type_initialization_checked (full_name, NULL, &error);
298 return_val_if_nok (&error, NULL);
305 * mono_runtime_class_init:
306 * \param vtable vtable that needs to be initialized
307 * This routine calls the class constructor for \p vtable.
310 mono_runtime_class_init (MonoVTable *vtable)
312 MONO_REQ_GC_UNSAFE_MODE;
315 mono_runtime_class_init_full (vtable, &error);
316 mono_error_assert_ok (&error);
320 * Returns TRUE if the lock was freed.
321 * LOCKING: Caller should hold type_initialization_lock.
324 unref_type_lock (TypeInitializationLock *lock)
326 --lock->waiting_count;
327 if (lock->waiting_count == 0) {
328 mono_coop_mutex_destroy (&lock->mutex);
329 mono_coop_cond_destroy (&lock->cond);
338 * mono_runtime_class_init_full:
339 * \param vtable that neeeds to be initialized
340 * \param error set on error
341 * \returns TRUE if class constructor \c .cctor has been initialized successfully, or FALSE otherwise and sets \p error.
344 mono_runtime_class_init_full (MonoVTable *vtable, MonoError *error)
346 MONO_REQ_GC_UNSAFE_MODE;
348 MonoMethod *method = NULL;
351 MonoDomain *domain = vtable->domain;
352 TypeInitializationLock *lock;
353 MonoNativeThreadId tid;
354 int do_initialization = 0;
355 MonoDomain *last_domain = NULL;
356 gboolean pending_tae = FALSE;
360 if (vtable->initialized)
363 klass = vtable->klass;
365 if (!klass->image->checked_module_cctor) {
366 mono_image_check_for_module_cctor (klass->image);
367 if (klass->image->has_module_cctor) {
368 MonoClass *module_klass;
369 MonoVTable *module_vtable;
371 module_klass = mono_class_get_checked (klass->image, MONO_TOKEN_TYPE_DEF | 1, error);
376 module_vtable = mono_class_vtable_full (vtable->domain, module_klass, error);
379 if (!mono_runtime_class_init_full (module_vtable, error))
383 method = mono_class_get_cctor (klass);
385 vtable->initialized = 1;
389 tid = mono_native_thread_id_get ();
392 * Due some preprocessing inside a global lock. If we are the first thread
393 * trying to initialize this class, create a separate lock+cond var, and
394 * acquire it before leaving the global lock. The other threads will wait
398 mono_type_initialization_lock ();
399 /* double check... */
400 if (vtable->initialized) {
401 mono_type_initialization_unlock ();
404 if (vtable->init_failed) {
405 mono_type_initialization_unlock ();
407 /* The type initialization already failed once, rethrow the same exception */
408 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
411 lock = (TypeInitializationLock *)g_hash_table_lookup (type_initialization_hash, vtable);
413 /* This thread will get to do the initialization */
414 if (mono_domain_get () != domain) {
415 /* Transfer into the target domain */
416 last_domain = mono_domain_get ();
417 if (!mono_domain_set (domain, FALSE)) {
418 vtable->initialized = 1;
419 mono_type_initialization_unlock ();
420 mono_error_set_exception_instance (error, mono_get_exception_appdomain_unloaded ());
424 lock = (TypeInitializationLock *)g_malloc0 (sizeof (TypeInitializationLock));
425 mono_coop_mutex_init_recursive (&lock->mutex);
426 mono_coop_cond_init (&lock->cond);
427 lock->initializing_tid = tid;
428 lock->waiting_count = 1;
430 g_hash_table_insert (type_initialization_hash, vtable, lock);
431 do_initialization = 1;
434 TypeInitializationLock *pending_lock;
436 if (mono_native_thread_id_equals (lock->initializing_tid, tid)) {
437 mono_type_initialization_unlock ();
440 /* see if the thread doing the initialization is already blocked on this thread */
441 gboolean is_blocked = TRUE;
442 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (lock->initializing_tid));
443 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
444 if (mono_native_thread_id_equals (pending_lock->initializing_tid, tid)) {
445 if (!pending_lock->done) {
446 mono_type_initialization_unlock ();
449 /* the thread doing the initialization is blocked on this thread,
450 but on a lock that has already been freed. It just hasn't got
456 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (pending_lock->initializing_tid));
458 ++lock->waiting_count;
459 /* record the fact that we are waiting on the initializing thread */
461 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
463 mono_type_initialization_unlock ();
465 if (do_initialization) {
466 MonoException *exc = NULL;
468 /* We are holding the per-vtable lock, do the actual initialization */
470 mono_threads_begin_abort_protected_block ();
471 mono_runtime_try_invoke (method, NULL, NULL, (MonoObject**) &exc, error);
472 mono_threads_end_abort_protected_block ();
474 //exception extracted, error will be set to the right value later
475 if (exc == NULL && !mono_error_ok (error))//invoking failed but exc was not set
476 exc = mono_error_convert_to_exception (error);
478 mono_error_cleanup (error);
482 /* If the initialization failed, mark the class as unusable. */
483 /* Avoid infinite loops */
485 (klass->image == mono_defaults.corlib &&
486 !strcmp (klass->name_space, "System") &&
487 !strcmp (klass->name, "TypeInitializationException")))) {
488 vtable->init_failed = 1;
490 if (klass->name_space && *klass->name_space)
491 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
493 full_name = g_strdup (klass->name);
495 MonoException *exc_to_throw = mono_get_exception_type_initialization_checked (full_name, exc, error);
498 mono_error_assert_ok (error); //We can't recover from this, no way to fail a type we can't alloc a failure.
501 * Store the exception object so it could be thrown on subsequent
504 mono_domain_lock (domain);
505 if (!domain->type_init_exception_hash)
506 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");
507 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
508 mono_domain_unlock (domain);
512 mono_domain_set (last_domain, TRUE);
514 /* Signal to the other threads that we are done */
515 mono_type_init_lock (lock);
517 mono_coop_cond_broadcast (&lock->cond);
518 mono_type_init_unlock (lock);
521 * This can happen if the cctor self-aborts. We need to reactivate tae
522 * (next interruption checkpoint will throw it) and make sure we won't
523 * throw tie for the type.
525 if (exc && mono_object_class (exc) == mono_defaults.threadabortexception_class) {
527 mono_thread_resume_interruption (FALSE);
530 /* this just blocks until the initializing thread is done */
531 mono_type_init_lock (lock);
533 mono_coop_cond_wait (&lock->cond, &lock->mutex);
534 mono_type_init_unlock (lock);
537 /* Do cleanup and setting vtable->initialized inside the global lock again */
538 mono_type_initialization_lock ();
539 if (!do_initialization)
540 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
541 gboolean deleted = unref_type_lock (lock);
543 g_hash_table_remove (type_initialization_hash, vtable);
544 /* Have to set this here since we check it inside the global lock */
545 if (do_initialization && !vtable->init_failed)
546 vtable->initialized = 1;
547 mono_type_initialization_unlock ();
549 /* If vtable init fails because of TAE, we don't throw TIE, only the TAE */
550 if (vtable->init_failed && !pending_tae) {
551 /* Either we were the initializing thread or we waited for the initialization */
552 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
559 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
561 MONO_REQ_GC_NEUTRAL_MODE;
563 MonoVTable *vtable = (MonoVTable*)key;
565 TypeInitializationLock *lock = (TypeInitializationLock*) value;
566 if (mono_native_thread_id_equals (lock->initializing_tid, MONO_UINT_TO_NATIVE_THREAD_ID (GPOINTER_TO_UINT (user))) && !lock->done) {
569 * Have to set this since it cannot be set by the normal code in
570 * mono_runtime_class_init (). In this case, the exception object is not stored,
571 * and get_type_init_exception_for_class () needs to be aware of this.
573 mono_type_init_lock (lock);
574 vtable->init_failed = 1;
575 mono_coop_cond_broadcast (&lock->cond);
576 mono_type_init_unlock (lock);
577 gboolean deleted = unref_type_lock (lock);
585 mono_release_type_locks (MonoInternalThread *thread)
587 MONO_REQ_GC_UNSAFE_MODE;
589 mono_type_initialization_lock ();
590 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, GUINT_TO_POINTER (thread->tid));
591 mono_type_initialization_unlock ();
594 #ifndef DISABLE_REMOTING
597 create_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error)
599 if (!callbacks.create_remoting_trampoline)
600 g_error ("remoting not installed");
601 return callbacks.create_remoting_trampoline (domain, method, target, error);
606 static MonoImtTrampolineBuilder imt_trampoline_builder;
607 static gboolean always_build_imt_trampolines;
609 #if (MONO_IMT_SIZE > 32)
610 #error "MONO_IMT_SIZE cannot be larger than 32"
614 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
616 memcpy (&callbacks, cbs, sizeof (*cbs));
619 MonoRuntimeCallbacks*
620 mono_get_runtime_callbacks (void)
626 mono_install_imt_trampoline_builder (MonoImtTrampolineBuilder func)
628 imt_trampoline_builder = func;
632 mono_set_always_build_imt_trampolines (gboolean value)
634 always_build_imt_trampolines = value;
638 * mono_compile_method:
639 * \param method The method to compile.
640 * This JIT-compiles the method, and returns the pointer to the native code
644 mono_compile_method (MonoMethod *method)
647 gpointer result = mono_compile_method_checked (method, &error);
648 mono_error_cleanup (&error);
653 * mono_compile_method_checked:
654 * \param method The method to compile.
655 * \param error set on error.
656 * This JIT-compiles the method, and returns the pointer to the native code
657 * produced. On failure returns NULL and sets \p error.
660 mono_compile_method_checked (MonoMethod *method, MonoError *error)
664 MONO_REQ_GC_NEUTRAL_MODE
668 g_assert (callbacks.compile_method);
669 res = callbacks.compile_method (method, error);
674 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper, MonoError *error)
678 MONO_REQ_GC_NEUTRAL_MODE;
681 res = callbacks.create_jump_trampoline (domain, method, add_sync_wrapper, error);
686 mono_runtime_create_delegate_trampoline (MonoClass *klass)
688 MONO_REQ_GC_NEUTRAL_MODE
690 g_assert (callbacks.create_delegate_trampoline);
691 return callbacks.create_delegate_trampoline (mono_domain_get (), klass);
695 * mono_runtime_free_method:
696 * \param domain domain where the method is hosted
697 * \param method method to release
698 * This routine is invoked to free the resources associated with
699 * a method that has been JIT compiled. This is used to discard
700 * methods that were used only temporarily (for example, used in marshalling)
703 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
705 MONO_REQ_GC_NEUTRAL_MODE
707 if (callbacks.free_method)
708 callbacks.free_method (domain, method);
710 mono_method_clear_object (domain, method);
712 mono_free_method (method);
716 * The vtables in the root appdomain are assumed to be reachable by other
717 * roots, and we don't use typed allocation in the other domains.
720 /* The sync block is no longer a GC pointer */
721 #define GC_HEADER_BITMAP (0)
723 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
726 compute_class_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
728 MONO_REQ_GC_NEUTRAL_MODE;
730 MonoClassField *field;
736 max_size = mono_class_data_size (klass) / sizeof (gpointer);
738 max_size = klass->instance_size / sizeof (gpointer);
739 if (max_size > size) {
740 g_assert (offset <= 0);
741 bitmap = (gsize *)g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
745 /* An Ephemeron cannot be marked by sgen */
746 if (mono_gc_is_moving () && !static_fields && klass->image == mono_defaults.corlib && !strcmp ("Ephemeron", klass->name)) {
748 memset (bitmap, 0, size / 8);
752 for (p = klass; p != NULL; p = p->parent) {
753 gpointer iter = NULL;
754 while ((field = mono_class_get_fields (p, &iter))) {
758 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
760 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
763 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
766 /* FIXME: should not happen, flag as type load error */
767 if (field->type->byref)
770 if (static_fields && field->offset == -1)
774 pos = field->offset / sizeof (gpointer);
777 type = mono_type_get_underlying_type (field->type);
778 switch (type->type) {
782 case MONO_TYPE_FNPTR:
784 case MONO_TYPE_STRING:
785 case MONO_TYPE_SZARRAY:
786 case MONO_TYPE_CLASS:
787 case MONO_TYPE_OBJECT:
788 case MONO_TYPE_ARRAY:
789 g_assert ((field->offset % sizeof(gpointer)) == 0);
791 g_assert (pos < size || pos <= max_size);
792 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
793 *max_set = MAX (*max_set, pos);
795 case MONO_TYPE_GENERICINST:
796 if (!mono_type_generic_inst_is_valuetype (type)) {
797 g_assert ((field->offset % sizeof(gpointer)) == 0);
799 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
800 *max_set = MAX (*max_set, pos);
805 case MONO_TYPE_VALUETYPE: {
806 MonoClass *fclass = mono_class_from_mono_type (field->type);
807 if (fclass->has_references) {
808 /* remove the object header */
809 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
823 case MONO_TYPE_BOOLEAN:
827 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
838 * mono_class_compute_bitmap:
840 * Mono internal function to compute a bitmap of reference fields in a class.
843 mono_class_compute_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
845 MONO_REQ_GC_NEUTRAL_MODE;
847 return compute_class_bitmap (klass, bitmap, size, offset, max_set, static_fields);
852 * similar to the above, but sets the bits in the bitmap for any non-ref field
853 * and ignores static fields
856 compute_class_non_ref_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset)
858 MonoClassField *field;
863 max_size = class->instance_size / sizeof (gpointer);
864 if (max_size >= size) {
865 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
868 for (p = class; p != NULL; p = p->parent) {
869 gpointer iter = NULL;
870 while ((field = mono_class_get_fields (p, &iter))) {
873 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
875 /* FIXME: should not happen, flag as type load error */
876 if (field->type->byref)
879 pos = field->offset / sizeof (gpointer);
882 type = mono_type_get_underlying_type (field->type);
883 switch (type->type) {
884 #if SIZEOF_VOID_P == 8
888 case MONO_TYPE_FNPTR:
893 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
894 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
895 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
898 #if SIZEOF_VOID_P == 4
902 case MONO_TYPE_FNPTR:
907 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
908 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
909 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
915 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
916 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
917 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
920 case MONO_TYPE_BOOLEAN:
923 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
925 case MONO_TYPE_STRING:
926 case MONO_TYPE_SZARRAY:
927 case MONO_TYPE_CLASS:
928 case MONO_TYPE_OBJECT:
929 case MONO_TYPE_ARRAY:
931 case MONO_TYPE_GENERICINST:
932 if (!mono_type_generic_inst_is_valuetype (type)) {
937 case MONO_TYPE_VALUETYPE: {
938 MonoClass *fclass = mono_class_from_mono_type (field->type);
939 /* remove the object header */
940 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
944 g_assert_not_reached ();
953 * mono_class_insecure_overlapping:
954 * check if a class with explicit layout has references and non-references
955 * fields overlapping.
957 * Returns: TRUE if it is insecure to load the type.
960 mono_class_insecure_overlapping (MonoClass *klass)
964 gsize default_bitmap [4] = {0};
966 gsize default_nrbitmap [4] = {0};
967 int i, insecure = FALSE;
970 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
971 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
973 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
974 int idx = i % (sizeof (bitmap [0]) * 8);
975 if (bitmap [idx] & nrbitmap [idx]) {
980 if (bitmap != default_bitmap)
982 if (nrbitmap != default_nrbitmap)
985 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
993 ves_icall_string_alloc (int length)
996 MonoString *str = mono_string_new_size_checked (mono_domain_get (), length, &error);
997 mono_error_set_pending_exception (&error);
1002 /* LOCKING: Acquires the loader lock */
1004 mono_class_compute_gc_descriptor (MonoClass *klass)
1006 MONO_REQ_GC_NEUTRAL_MODE;
1010 gsize default_bitmap [4] = {0};
1011 static gboolean gcj_inited = FALSE;
1012 MonoGCDescriptor gc_descr;
1015 mono_loader_lock ();
1017 mono_register_jit_icall (ves_icall_object_new_fast, "ves_icall_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
1018 mono_register_jit_icall (ves_icall_string_alloc, "ves_icall_string_alloc", mono_create_icall_signature ("object int"), FALSE);
1021 mono_loader_unlock ();
1025 mono_class_init (klass);
1027 if (klass->gc_descr_inited)
1030 bitmap = default_bitmap;
1031 if (klass == mono_defaults.string_class) {
1032 gc_descr = mono_gc_make_descr_for_string (bitmap, 2);
1033 } else if (klass->rank) {
1034 mono_class_compute_gc_descriptor (klass->element_class);
1035 if (MONO_TYPE_IS_REFERENCE (&klass->element_class->byval_arg)) {
1037 gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
1038 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1039 class->name_space, class->name);*/
1041 /* remove the object header */
1042 bitmap = compute_class_bitmap (klass->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
1043 gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, bitmap, mono_array_element_size (klass) / sizeof (gpointer), mono_array_element_size (klass));
1044 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1045 class->name_space, class->name);*/
1046 if (bitmap != default_bitmap)
1050 /*static int count = 0;
1053 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1054 gc_descr = mono_gc_make_descr_for_object (bitmap, max_set + 1, klass->instance_size);
1056 if (class->gc_descr == MONO_GC_DESCRIPTOR_NULL)
1057 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
1059 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
1060 if (bitmap != default_bitmap)
1064 /* Publish the data */
1065 mono_loader_lock ();
1066 klass->gc_descr = gc_descr;
1067 mono_memory_barrier ();
1068 klass->gc_descr_inited = TRUE;
1069 mono_loader_unlock ();
1073 * field_is_special_static:
1074 * @fklass: The MonoClass to look up.
1075 * @field: The MonoClassField describing the field.
1077 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1078 * SPECIAL_STATIC_NONE otherwise.
1081 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1083 MONO_REQ_GC_NEUTRAL_MODE;
1086 MonoCustomAttrInfo *ainfo;
1088 ainfo = mono_custom_attrs_from_field_checked (fklass, field, &error);
1089 mono_error_cleanup (&error); /* FIXME don't swallow the error? */
1092 for (i = 0; i < ainfo->num_attrs; ++i) {
1093 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1094 if (klass->image == mono_defaults.corlib) {
1095 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1096 mono_custom_attrs_free (ainfo);
1097 return SPECIAL_STATIC_THREAD;
1099 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1100 mono_custom_attrs_free (ainfo);
1101 return SPECIAL_STATIC_CONTEXT;
1105 mono_custom_attrs_free (ainfo);
1106 return SPECIAL_STATIC_NONE;
1109 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1110 #define mix(a,b,c) { \
1111 a -= c; a ^= rot(c, 4); c += b; \
1112 b -= a; b ^= rot(a, 6); a += c; \
1113 c -= b; c ^= rot(b, 8); b += a; \
1114 a -= c; a ^= rot(c,16); c += b; \
1115 b -= a; b ^= rot(a,19); a += c; \
1116 c -= b; c ^= rot(b, 4); b += a; \
1118 #define final(a,b,c) { \
1119 c ^= b; c -= rot(b,14); \
1120 a ^= c; a -= rot(c,11); \
1121 b ^= a; b -= rot(a,25); \
1122 c ^= b; c -= rot(b,16); \
1123 a ^= c; a -= rot(c,4); \
1124 b ^= a; b -= rot(a,14); \
1125 c ^= b; c -= rot(b,24); \
1129 * mono_method_get_imt_slot:
1131 * The IMT slot is embedded into AOTed code, so this must return the same value
1132 * for the same method across all executions. This means:
1133 * - pointers shouldn't be used as hash values.
1134 * - mono_metadata_str_hash () should be used for hashing strings.
1137 mono_method_get_imt_slot (MonoMethod *method)
1139 MONO_REQ_GC_NEUTRAL_MODE;
1141 MonoMethodSignature *sig;
1143 guint32 *hashes_start, *hashes;
1147 /* This can be used to stress tests the collision code */
1151 * We do this to simplify generic sharing. It will hurt
1152 * performance in cases where a class implements two different
1153 * instantiations of the same generic interface.
1154 * The code in build_imt_slots () depends on this.
1156 if (method->is_inflated)
1157 method = ((MonoMethodInflated*)method)->declaring;
1159 sig = mono_method_signature (method);
1160 hashes_count = sig->param_count + 4;
1161 hashes_start = (guint32 *)malloc (hashes_count * sizeof (guint32));
1162 hashes = hashes_start;
1164 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1165 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1166 method->klass->name_space, method->klass->name, method->name);
1169 /* Initialize hashes */
1170 hashes [0] = mono_metadata_str_hash (method->klass->name);
1171 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1172 hashes [2] = mono_metadata_str_hash (method->name);
1173 hashes [3] = mono_metadata_type_hash (sig->ret);
1174 for (i = 0; i < sig->param_count; i++) {
1175 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1178 /* Setup internal state */
1179 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1181 /* Handle most of the hashes */
1182 while (hashes_count > 3) {
1191 /* Handle the last 3 hashes (all the case statements fall through) */
1192 switch (hashes_count) {
1193 case 3 : c += hashes [2];
1194 case 2 : b += hashes [1];
1195 case 1 : a += hashes [0];
1197 case 0: /* nothing left to add */
1201 g_free (hashes_start);
1202 /* Report the result */
1203 return c % MONO_IMT_SIZE;
1212 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1213 MONO_REQ_GC_NEUTRAL_MODE;
1215 guint32 imt_slot = mono_method_get_imt_slot (method);
1216 MonoImtBuilderEntry *entry;
1218 if (slot_num >= 0 && imt_slot != slot_num) {
1219 /* we build just a single imt slot and this is not it */
1223 entry = (MonoImtBuilderEntry *)g_malloc0 (sizeof (MonoImtBuilderEntry));
1224 entry->key = method;
1225 entry->value.vtable_slot = vtable_slot;
1226 entry->next = imt_builder [imt_slot];
1227 if (imt_builder [imt_slot] != NULL) {
1228 entry->children = imt_builder [imt_slot]->children + 1;
1229 if (entry->children == 1) {
1230 mono_stats.imt_slots_with_collisions++;
1231 *imt_collisions_bitmap |= (1 << imt_slot);
1234 entry->children = 0;
1235 mono_stats.imt_used_slots++;
1237 imt_builder [imt_slot] = entry;
1240 char *method_name = mono_method_full_name (method, TRUE);
1241 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1242 method, method_name, imt_slot, vtable_slot, entry->children);
1243 g_free (method_name);
1250 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1252 MonoMethod *method = e->key;
1253 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1257 method->klass->name_space,
1258 method->klass->name,
1261 printf (" * %s: NULL\n", message);
1267 compare_imt_builder_entries (const void *p1, const void *p2) {
1268 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1269 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1271 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1275 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1277 MONO_REQ_GC_NEUTRAL_MODE;
1279 int count = end - start;
1280 int chunk_start = out_array->len;
1283 for (i = start; i < end; ++i) {
1284 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1285 item->key = sorted_array [i]->key;
1286 item->value = sorted_array [i]->value;
1287 item->has_target_code = sorted_array [i]->has_target_code;
1288 item->is_equals = TRUE;
1290 item->check_target_idx = out_array->len + 1;
1292 item->check_target_idx = 0;
1293 g_ptr_array_add (out_array, item);
1296 int middle = start + count / 2;
1297 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1299 item->key = sorted_array [middle]->key;
1300 item->is_equals = FALSE;
1301 g_ptr_array_add (out_array, item);
1302 imt_emit_ir (sorted_array, start, middle, out_array);
1303 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1309 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1310 MONO_REQ_GC_NEUTRAL_MODE;
1312 int number_of_entries = entries->children + 1;
1313 MonoImtBuilderEntry **sorted_array = (MonoImtBuilderEntry **)malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1314 GPtrArray *result = g_ptr_array_new ();
1315 MonoImtBuilderEntry *current_entry;
1318 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1319 sorted_array [i] = current_entry;
1321 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1323 /*for (i = 0; i < number_of_entries; i++) {
1324 print_imt_entry (" sorted array:", sorted_array [i], i);
1327 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1329 g_free (sorted_array);
1334 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1336 MONO_REQ_GC_NEUTRAL_MODE;
1338 if (imt_builder_entry != NULL) {
1339 if (imt_builder_entry->children == 0 && !fail_tramp && !always_build_imt_trampolines) {
1340 /* No collision, return the vtable slot contents */
1341 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1343 /* Collision, build the trampoline */
1344 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1347 result = imt_trampoline_builder (vtable, domain,
1348 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1349 for (i = 0; i < imt_ir->len; ++i)
1350 g_free (g_ptr_array_index (imt_ir, i));
1351 g_ptr_array_free (imt_ir, TRUE);
1363 static MonoImtBuilderEntry*
1364 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1367 * LOCKING: requires the loader and domain locks.
1371 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1373 MONO_REQ_GC_NEUTRAL_MODE;
1377 guint32 imt_collisions_bitmap = 0;
1378 MonoImtBuilderEntry **imt_builder = (MonoImtBuilderEntry **)calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1379 int method_count = 0;
1380 gboolean record_method_count_for_max_collisions = FALSE;
1381 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1384 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1386 for (i = 0; i < klass->interface_offsets_count; ++i) {
1387 MonoClass *iface = klass->interfaces_packed [i];
1388 int interface_offset = klass->interface_offsets_packed [i];
1389 int method_slot_in_interface, vt_slot;
1391 if (mono_class_has_variant_generic_params (iface))
1392 has_variant_iface = TRUE;
1394 mono_class_setup_methods (iface);
1395 vt_slot = interface_offset;
1396 int mcount = mono_class_get_method_count (iface);
1397 for (method_slot_in_interface = 0; method_slot_in_interface < mcount; method_slot_in_interface++) {
1400 if (slot_num >= 0 && mono_class_is_ginst (iface)) {
1402 * The imt slot of the method is the same as for its declaring method,
1403 * see the comment in mono_method_get_imt_slot (), so we can
1404 * avoid inflating methods which will be discarded by
1405 * add_imt_builder_entry anyway.
1407 method = mono_class_get_method_by_index (mono_class_get_generic_class (iface)->container_class, method_slot_in_interface);
1408 if (mono_method_get_imt_slot (method) != slot_num) {
1413 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1414 if (method->is_generic) {
1415 has_generic_virtual = TRUE;
1420 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1421 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1426 if (extra_interfaces) {
1427 int interface_offset = klass->vtable_size;
1429 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1430 MonoClass* iface = (MonoClass *)list_item->data;
1431 int method_slot_in_interface;
1432 int mcount = mono_class_get_method_count (iface);
1433 for (method_slot_in_interface = 0; method_slot_in_interface < mcount; method_slot_in_interface++) {
1434 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1436 if (method->is_generic)
1437 has_generic_virtual = TRUE;
1438 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1440 interface_offset += mcount;
1443 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1444 /* overwrite the imt slot only if we're building all the entries or if
1445 * we're building this specific one
1447 if (slot_num < 0 || i == slot_num) {
1448 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1451 if (imt_builder [i]) {
1452 MonoImtBuilderEntry *entry;
1454 /* Link entries with imt_builder [i] */
1455 for (entry = entries; entry->next; entry = entry->next) {
1457 MonoMethod *method = (MonoMethod*)entry->key;
1458 char *method_name = mono_method_full_name (method, TRUE);
1459 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1460 g_free (method_name);
1463 entry->next = imt_builder [i];
1464 entries->children += imt_builder [i]->children + 1;
1466 imt_builder [i] = entries;
1469 if (has_generic_virtual || has_variant_iface) {
1471 * There might be collisions later when the the trampoline is expanded.
1473 imt_collisions_bitmap |= (1 << i);
1476 * The IMT trampoline might be called with an instance of one of the
1477 * generic virtual methods, so has to fallback to the IMT trampoline.
1479 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline (vt, i));
1481 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1484 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1488 if (imt_builder [i] != NULL) {
1489 int methods_in_slot = imt_builder [i]->children + 1;
1490 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1491 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1492 record_method_count_for_max_collisions = TRUE;
1494 method_count += methods_in_slot;
1498 mono_stats.imt_number_of_methods += method_count;
1499 if (record_method_count_for_max_collisions) {
1500 mono_stats.imt_method_count_when_max_collisions = method_count;
1503 for (i = 0; i < MONO_IMT_SIZE; i++) {
1504 MonoImtBuilderEntry* entry = imt_builder [i];
1505 while (entry != NULL) {
1506 MonoImtBuilderEntry* next = entry->next;
1511 g_free (imt_builder);
1512 /* we OR the bitmap since we may build just a single imt slot at a time */
1513 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1517 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1518 MONO_REQ_GC_NEUTRAL_MODE;
1520 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1524 * mono_vtable_build_imt_slot:
1525 * \param vtable virtual object table struct
1526 * \param imt_slot slot in the IMT table
1527 * Fill the given \p imt_slot in the IMT table of \p vtable with
1528 * a trampoline or a trampoline for the case of collisions.
1529 * This is part of the internal mono API.
1530 * LOCKING: Take the domain lock.
1533 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1535 MONO_REQ_GC_NEUTRAL_MODE;
1537 gpointer *imt = (gpointer*)vtable;
1538 imt -= MONO_IMT_SIZE;
1539 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1541 /* no support for extra interfaces: the proxy objects will need
1542 * to build the complete IMT
1543 * Update and heck needs to ahppen inside the proper domain lock, as all
1544 * the changes made to a MonoVTable.
1546 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1547 mono_domain_lock (vtable->domain);
1548 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1549 if (!callbacks.imt_entry_inited (vtable, imt_slot))
1550 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1551 mono_domain_unlock (vtable->domain);
1552 mono_loader_unlock ();
1555 #define THUNK_THRESHOLD 10
1558 * mono_method_alloc_generic_virtual_trampoline:
1559 * \param domain a domain
1560 * \param size size in bytes
1561 * Allocs \p size bytes to be used for the code of a generic virtual
1562 * trampoline. It's either allocated from the domain's code manager or
1563 * reused from a previously invalidated piece.
1564 * LOCKING: The domain lock must be held.
1567 mono_method_alloc_generic_virtual_trampoline (MonoDomain *domain, int size)
1569 MONO_REQ_GC_NEUTRAL_MODE;
1571 static gboolean inited = FALSE;
1572 static int generic_virtual_trampolines_size = 0;
1575 mono_counters_register ("Generic virtual trampoline bytes",
1576 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_trampolines_size);
1579 generic_virtual_trampolines_size += size;
1581 return mono_domain_code_reserve (domain, size);
1584 typedef struct _GenericVirtualCase {
1588 struct _GenericVirtualCase *next;
1589 } GenericVirtualCase;
1592 * get_generic_virtual_entries:
1594 * Return IMT entries for the generic virtual method instances and
1595 * variant interface methods for vtable slot
1598 static MonoImtBuilderEntry*
1599 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1601 MONO_REQ_GC_NEUTRAL_MODE;
1603 GenericVirtualCase *list;
1604 MonoImtBuilderEntry *entries;
1606 mono_domain_lock (domain);
1607 if (!domain->generic_virtual_cases)
1608 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1610 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1613 for (; list; list = list->next) {
1614 MonoImtBuilderEntry *entry;
1616 if (list->count < THUNK_THRESHOLD)
1619 entry = g_new0 (MonoImtBuilderEntry, 1);
1620 entry->key = list->method;
1621 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1622 entry->has_target_code = 1;
1624 entry->children = entries->children + 1;
1625 entry->next = entries;
1629 mono_domain_unlock (domain);
1631 /* FIXME: Leaking memory ? */
1636 * \param domain a domain
1637 * \param vtable_slot pointer to the vtable slot
1638 * \param method the inflated generic virtual method
1639 * \param code the method's code
1641 * Registers a call via unmanaged code to a generic virtual method
1642 * instantiation or variant interface method. If the number of calls reaches a threshold
1643 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1644 * virtual method trampoline.
1647 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1648 gpointer *vtable_slot,
1649 MonoMethod *method, gpointer code)
1651 MONO_REQ_GC_NEUTRAL_MODE;
1653 static gboolean inited = FALSE;
1654 static int num_added = 0;
1655 static int num_freed = 0;
1657 GenericVirtualCase *gvc, *list;
1658 MonoImtBuilderEntry *entries;
1662 mono_domain_lock (domain);
1663 if (!domain->generic_virtual_cases)
1664 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1667 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1668 mono_counters_register ("Freed IMT trampolines", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_freed);
1672 /* Check whether the case was already added */
1673 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1676 if (gvc->method == method)
1681 /* If not found, make a new one */
1683 gvc = (GenericVirtualCase *)mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1684 gvc->method = method;
1687 gvc->next = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1689 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1694 if (++gvc->count == THUNK_THRESHOLD) {
1695 gpointer *old_thunk = (void **)*vtable_slot;
1696 gpointer vtable_trampoline = NULL;
1697 gpointer imt_trampoline = NULL;
1699 if ((gpointer)vtable_slot < (gpointer)vtable) {
1700 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1701 int imt_slot = MONO_IMT_SIZE + displacement;
1703 /* Force the rebuild of the trampoline at the next call */
1704 imt_trampoline = callbacks.get_imt_trampoline (vtable, imt_slot);
1705 *vtable_slot = imt_trampoline;
1707 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline (vtable, (gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1709 entries = get_generic_virtual_entries (domain, vtable_slot);
1711 sorted = imt_sort_slot_entries (entries);
1713 *vtable_slot = imt_trampoline_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1717 MonoImtBuilderEntry *next = entries->next;
1722 for (i = 0; i < sorted->len; ++i)
1723 g_free (g_ptr_array_index (sorted, i));
1724 g_ptr_array_free (sorted, TRUE);
1726 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1731 mono_domain_unlock (domain);
1734 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error);
1737 * mono_class_vtable:
1738 * \param domain the application domain
1739 * \param class the class to initialize
1740 * VTables are domain specific because we create domain specific code, and
1741 * they contain the domain specific static class data.
1742 * On failure, NULL is returned, and \c class->exception_type is set.
1745 mono_class_vtable (MonoDomain *domain, MonoClass *klass)
1748 MonoVTable* vtable = mono_class_vtable_full (domain, klass, &error);
1749 mono_error_cleanup (&error);
1754 * mono_class_vtable_full:
1755 * \param domain the application domain
1756 * \param class the class to initialize
1757 * \param error set on failure.
1758 * VTables are domain specific because we create domain specific code, and
1759 * they contain the domain specific static class data.
1762 mono_class_vtable_full (MonoDomain *domain, MonoClass *klass, MonoError *error)
1764 MONO_REQ_GC_UNSAFE_MODE;
1766 MonoClassRuntimeInfo *runtime_info;
1772 if (mono_class_has_failure (klass)) {
1773 mono_error_set_for_class_failure (error, klass);
1777 /* this check can be inlined in jitted code, too */
1778 runtime_info = klass->runtime_info;
1779 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1780 return runtime_info->domain_vtables [domain->domain_id];
1781 return mono_class_create_runtime_vtable (domain, klass, error);
1785 * mono_class_try_get_vtable:
1786 * \param domain the application domain
1787 * \param class the class to initialize
1788 * This function tries to get the associated vtable from \p class if
1789 * it was already created.
1792 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *klass)
1794 MONO_REQ_GC_NEUTRAL_MODE;
1796 MonoClassRuntimeInfo *runtime_info;
1800 runtime_info = klass->runtime_info;
1801 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1802 return runtime_info->domain_vtables [domain->domain_id];
1807 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1809 MONO_REQ_GC_NEUTRAL_MODE;
1811 size_t alloc_offset;
1814 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1815 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1816 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1818 if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1819 g_assert ((imt_table_bytes & 7) == 4);
1826 return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1830 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error)
1832 MONO_REQ_GC_UNSAFE_MODE;
1835 MonoClassRuntimeInfo *runtime_info, *old_info;
1836 MonoClassField *field;
1838 int i, vtable_slots;
1839 size_t imt_table_bytes;
1841 guint32 vtable_size, class_size;
1843 gpointer *interface_offsets;
1847 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1848 mono_domain_lock (domain);
1849 runtime_info = klass->runtime_info;
1850 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1851 mono_domain_unlock (domain);
1852 mono_loader_unlock ();
1853 return runtime_info->domain_vtables [domain->domain_id];
1855 if (!klass->inited || mono_class_has_failure (klass)) {
1856 if (!mono_class_init (klass) || mono_class_has_failure (klass)) {
1857 mono_domain_unlock (domain);
1858 mono_loader_unlock ();
1859 mono_error_set_for_class_failure (error, klass);
1864 /* Array types require that their element type be valid*/
1865 if (klass->byval_arg.type == MONO_TYPE_ARRAY || klass->byval_arg.type == MONO_TYPE_SZARRAY) {
1866 MonoClass *element_class = klass->element_class;
1867 if (!element_class->inited)
1868 mono_class_init (element_class);
1870 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1871 if (!mono_class_has_failure (element_class) && !element_class->vtable_size)
1872 mono_class_setup_vtable (element_class);
1874 if (mono_class_has_failure (element_class)) {
1875 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1876 if (!mono_class_has_failure (klass))
1877 mono_class_set_type_load_failure (klass, "");
1878 mono_domain_unlock (domain);
1879 mono_loader_unlock ();
1880 mono_error_set_for_class_failure (error, klass);
1886 * For some classes, mono_class_init () already computed klass->vtable_size, and
1887 * that is all that is needed because of the vtable trampolines.
1889 if (!klass->vtable_size)
1890 mono_class_setup_vtable (klass);
1892 if (mono_class_is_ginst (klass) && !klass->vtable)
1893 mono_class_check_vtable_constraints (klass, NULL);
1895 /* Initialize klass->has_finalize */
1896 mono_class_has_finalizer (klass);
1898 if (mono_class_has_failure (klass)) {
1899 mono_domain_unlock (domain);
1900 mono_loader_unlock ();
1901 mono_error_set_for_class_failure (error, klass);
1905 vtable_slots = klass->vtable_size;
1906 /* we add an additional vtable slot to store the pointer to static field data only when needed */
1907 class_size = mono_class_data_size (klass);
1911 if (klass->interface_offsets_count) {
1912 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1913 mono_stats.imt_number_of_tables++;
1914 mono_stats.imt_tables_size += imt_table_bytes;
1916 imt_table_bytes = 0;
1919 vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
1921 mono_stats.used_class_count++;
1922 mono_stats.class_vtable_size += vtable_size;
1924 interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
1925 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1926 g_assert (!((gsize)vt & 7));
1929 vt->rank = klass->rank;
1930 vt->domain = domain;
1932 mono_class_compute_gc_descriptor (klass);
1935 * We can't use typed allocation in the non-root domains, since the
1936 * collector needs the GC descriptor stored in the vtable even after
1937 * the mempool containing the vtable is destroyed when the domain is
1938 * unloaded. An alternative might be to allocate vtables in the GC
1939 * heap, but this does not seem to work (it leads to crashes inside
1940 * libgc). If that approach is tried, two gc descriptors need to be
1941 * allocated for each class: one for the root domain, and one for all
1942 * other domains. The second descriptor should contain a bit for the
1943 * vtable field in MonoObject, since we can no longer assume the
1944 * vtable is reachable by other roots after the appdomain is unloaded.
1946 if (!mono_gc_is_moving () && domain != mono_get_root_domain () && !mono_dont_free_domains)
1947 vt->gc_descr = MONO_GC_DESCRIPTOR_NULL;
1949 vt->gc_descr = klass->gc_descr;
1951 gc_bits = mono_gc_get_vtable_bits (klass);
1952 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
1954 vt->gc_bits = gc_bits;
1957 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
1958 if (klass->has_static_refs) {
1959 MonoGCDescriptor statics_gc_descr;
1961 gsize default_bitmap [4] = {0};
1964 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1965 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], klass->name_space, klass->name, class_size);*/
1966 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1967 vt->vtable [klass->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr, MONO_ROOT_SOURCE_STATIC, "managed static variables");
1968 if (bitmap != default_bitmap)
1971 vt->vtable [klass->vtable_size] = mono_domain_alloc0 (domain, class_size);
1973 vt->has_static_fields = TRUE;
1974 mono_stats.class_static_data_size += class_size;
1978 while ((field = mono_class_get_fields (klass, &iter))) {
1979 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1981 if (mono_field_is_deleted (field))
1983 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1984 gint32 special_static = klass->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (klass, field);
1985 if (special_static != SPECIAL_STATIC_NONE) {
1986 guint32 size, offset;
1988 gsize default_bitmap [4] = {0};
1993 if (mono_type_is_reference (field->type)) {
1994 default_bitmap [0] = 1;
1996 bitmap = default_bitmap;
1997 } else if (mono_type_is_struct (field->type)) {
1998 fclass = mono_class_from_mono_type (field->type);
1999 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
2000 numbits = max_set + 1;
2002 default_bitmap [0] = 0;
2004 bitmap = default_bitmap;
2006 size = mono_type_size (field->type, &align);
2007 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
2008 if (!domain->special_static_fields)
2009 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2010 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2011 if (bitmap != default_bitmap)
2014 * This marks the field as special static to speed up the
2015 * checks in mono_field_static_get/set_value ().
2021 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2022 MonoClass *fklass = mono_class_from_mono_type (field->type);
2023 const char *data = mono_field_get_data (field);
2025 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2026 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2027 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2030 if (fklass->valuetype) {
2031 memcpy (t, data, mono_class_value_size (fklass, NULL));
2033 /* it's a pointer type: add check */
2034 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2041 vt->max_interface_id = klass->max_interface_id;
2042 vt->interface_bitmap = klass->interface_bitmap;
2044 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2045 // class->name, klass->interface_offsets_count);
2047 /* Initialize vtable */
2048 if (callbacks.get_vtable_trampoline) {
2049 // This also covers the AOT case
2050 for (i = 0; i < klass->vtable_size; ++i) {
2051 vt->vtable [i] = callbacks.get_vtable_trampoline (vt, i);
2054 mono_class_setup_vtable (klass);
2056 for (i = 0; i < klass->vtable_size; ++i) {
2059 cm = klass->vtable [i];
2061 vt->vtable [i] = callbacks.create_jit_trampoline (domain, cm, error);
2062 if (!is_ok (error)) {
2063 mono_domain_unlock (domain);
2064 mono_loader_unlock ();
2071 if (imt_table_bytes) {
2072 /* Now that the vtable is full, we can actually fill up the IMT */
2073 for (i = 0; i < MONO_IMT_SIZE; ++i)
2074 interface_offsets [i] = callbacks.get_imt_trampoline (vt, i);
2078 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2079 * re-acquire them and check if another thread has created the vtable in the meantime.
2081 /* Special case System.MonoType to avoid infinite recursion */
2082 if (klass != mono_defaults.runtimetype_class) {
2083 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2084 if (!is_ok (error)) {
2085 mono_domain_unlock (domain);
2086 mono_loader_unlock ();
2090 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2091 /* This is unregistered in
2092 unregister_vtable_reflection_type() in
2094 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2097 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (klass));
2099 /* class_vtable_array keeps an array of created vtables
2101 g_ptr_array_add (domain->class_vtable_array, vt);
2102 /* klass->runtime_info is protected by the loader lock, both when
2103 * it it enlarged and when it is stored info.
2107 * Store the vtable in klass->runtime_info.
2108 * klass->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2110 mono_memory_barrier ();
2112 old_info = klass->runtime_info;
2113 if (old_info && old_info->max_domain >= domain->domain_id) {
2114 /* someone already created a large enough runtime info */
2115 old_info->domain_vtables [domain->domain_id] = vt;
2117 int new_size = domain->domain_id;
2119 new_size = MAX (new_size, old_info->max_domain);
2121 /* make the new size a power of two */
2123 while (new_size > i)
2126 /* this is a bounded memory retention issue: may want to
2127 * handle it differently when we'll have a rcu-like system.
2129 runtime_info = (MonoClassRuntimeInfo *)mono_image_alloc0 (klass->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2130 runtime_info->max_domain = new_size - 1;
2131 /* copy the stuff from the older info */
2133 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2135 runtime_info->domain_vtables [domain->domain_id] = vt;
2137 mono_memory_barrier ();
2138 klass->runtime_info = runtime_info;
2141 if (klass == mono_defaults.runtimetype_class) {
2142 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2143 if (!is_ok (error)) {
2144 mono_domain_unlock (domain);
2145 mono_loader_unlock ();
2149 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2150 /* This is unregistered in
2151 unregister_vtable_reflection_type() in
2153 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2156 mono_domain_unlock (domain);
2157 mono_loader_unlock ();
2159 /* make sure the parent is initialized */
2160 /*FIXME shouldn't this fail the current type?*/
2162 mono_class_vtable_full (domain, klass->parent, error);
2167 #ifndef DISABLE_REMOTING
2169 * mono_class_proxy_vtable:
2170 * \param domain the application domain
2171 * \param remove_class the remote class
2172 * \param error set on error
2173 * Creates a vtable for transparent proxies. It is basically
2174 * a copy of the real vtable of the class wrapped in \p remote_class,
2175 * but all function pointers invoke the remoting functions, and
2176 * \c vtable->klass points to the transparent proxy class, and not to \p class.
2178 * On failure returns NULL and sets \p error
2181 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type, MonoError *error)
2183 MONO_REQ_GC_UNSAFE_MODE;
2185 MonoVTable *vt, *pvt;
2186 int i, j, vtsize, extra_interface_vtsize = 0;
2187 guint32 max_interface_id;
2189 GSList *extra_interfaces = NULL;
2190 MonoClass *klass = remote_class->proxy_class;
2191 gpointer *interface_offsets;
2192 uint8_t *bitmap = NULL;
2194 size_t imt_table_bytes;
2196 #ifdef COMPRESSED_INTERFACE_BITMAP
2202 vt = mono_class_vtable (domain, klass);
2203 g_assert (vt); /*FIXME property handle failure*/
2204 max_interface_id = vt->max_interface_id;
2206 /* Calculate vtable space for extra interfaces */
2207 for (j = 0; j < remote_class->interface_count; j++) {
2208 MonoClass* iclass = remote_class->interfaces[j];
2212 /*FIXME test for interfaces with variant generic arguments*/
2213 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, iclass->interface_id))
2214 continue; /* interface implemented by the class */
2215 if (g_slist_find (extra_interfaces, iclass))
2218 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2220 method_count = mono_class_num_methods (iclass);
2222 ifaces = mono_class_get_implemented_interfaces (iclass, error);
2226 for (i = 0; i < ifaces->len; ++i) {
2227 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2228 /*FIXME test for interfaces with variant generic arguments*/
2229 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, ic->interface_id))
2230 continue; /* interface implemented by the class */
2231 if (g_slist_find (extra_interfaces, ic))
2233 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2234 method_count += mono_class_num_methods (ic);
2236 g_ptr_array_free (ifaces, TRUE);
2240 extra_interface_vtsize += method_count * sizeof (gpointer);
2241 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2244 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2245 mono_stats.imt_number_of_tables++;
2246 mono_stats.imt_tables_size += imt_table_bytes;
2248 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer);
2250 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2252 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2253 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2254 g_assert (!((gsize)pvt & 7));
2256 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer));
2258 pvt->klass = mono_defaults.transparent_proxy_class;
2259 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2260 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2262 /* initialize vtable */
2263 mono_class_setup_vtable (klass);
2264 for (i = 0; i < klass->vtable_size; ++i) {
2267 if ((cm = klass->vtable [i])) {
2268 pvt->vtable [i] = create_remoting_trampoline (domain, cm, target_type, error);
2272 pvt->vtable [i] = NULL;
2275 if (mono_class_is_abstract (klass)) {
2276 /* create trampolines for abstract methods */
2277 for (k = klass; k; k = k->parent) {
2279 gpointer iter = NULL;
2280 while ((m = mono_class_get_methods (k, &iter)))
2281 if (!pvt->vtable [m->slot]) {
2282 pvt->vtable [m->slot] = create_remoting_trampoline (domain, m, target_type, error);
2289 pvt->max_interface_id = max_interface_id;
2290 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2291 #ifdef COMPRESSED_INTERFACE_BITMAP
2292 bitmap = (uint8_t *)g_malloc0 (bsize);
2294 bitmap = (uint8_t *)mono_domain_alloc0 (domain, bsize);
2297 for (i = 0; i < klass->interface_offsets_count; ++i) {
2298 int interface_id = klass->interfaces_packed [i]->interface_id;
2299 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2302 if (extra_interfaces) {
2303 int slot = klass->vtable_size;
2309 /* Create trampolines for the methods of the interfaces */
2310 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2311 interf = (MonoClass *)list_item->data;
2313 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2317 while ((cm = mono_class_get_methods (interf, &iter))) {
2318 pvt->vtable [slot + j++] = create_remoting_trampoline (domain, cm, target_type, error);
2323 slot += mono_class_num_methods (interf);
2327 /* Now that the vtable is full, we can actually fill up the IMT */
2328 build_imt (klass, pvt, domain, interface_offsets, extra_interfaces);
2329 if (extra_interfaces) {
2330 g_slist_free (extra_interfaces);
2333 #ifdef COMPRESSED_INTERFACE_BITMAP
2334 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2335 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2336 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2339 pvt->interface_bitmap = bitmap;
2343 if (extra_interfaces)
2344 g_slist_free (extra_interfaces);
2345 #ifdef COMPRESSED_INTERFACE_BITMAP
2351 #endif /* DISABLE_REMOTING */
2354 * mono_class_field_is_special_static:
2355 * \returns whether \p field is a thread/context static field.
2358 mono_class_field_is_special_static (MonoClassField *field)
2360 MONO_REQ_GC_NEUTRAL_MODE
2362 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2364 if (mono_field_is_deleted (field))
2366 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2367 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2374 * mono_class_field_get_special_static_type:
2375 * \param field The \c MonoClassField describing the field.
2376 * \returns \c SPECIAL_STATIC_THREAD if the field is thread static, \c SPECIAL_STATIC_CONTEXT if it is context static,
2377 * \c SPECIAL_STATIC_NONE otherwise.
2380 mono_class_field_get_special_static_type (MonoClassField *field)
2382 MONO_REQ_GC_NEUTRAL_MODE
2384 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2385 return SPECIAL_STATIC_NONE;
2386 if (mono_field_is_deleted (field))
2387 return SPECIAL_STATIC_NONE;
2388 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2389 return field_is_special_static (field->parent, field);
2390 return SPECIAL_STATIC_NONE;
2394 * mono_class_has_special_static_fields:
2395 * \returns whether \p klass has any thread/context static fields.
2398 mono_class_has_special_static_fields (MonoClass *klass)
2400 MONO_REQ_GC_NEUTRAL_MODE
2402 MonoClassField *field;
2406 while ((field = mono_class_get_fields (klass, &iter))) {
2407 g_assert (field->parent == klass);
2408 if (mono_class_field_is_special_static (field))
2415 #ifndef DISABLE_REMOTING
2417 * create_remote_class_key:
2418 * Creates an array of pointers that can be used as a hash key for a remote class.
2419 * The first element of the array is the number of pointers.
2422 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2424 MONO_REQ_GC_NEUTRAL_MODE;
2429 if (remote_class == NULL) {
2430 if (mono_class_is_interface (extra_class)) {
2431 key = (void **)g_malloc (sizeof(gpointer) * 3);
2432 key [0] = GINT_TO_POINTER (2);
2433 key [1] = mono_defaults.marshalbyrefobject_class;
2434 key [2] = extra_class;
2436 key = (void **)g_malloc (sizeof(gpointer) * 2);
2437 key [0] = GINT_TO_POINTER (1);
2438 key [1] = extra_class;
2441 if (extra_class != NULL && mono_class_is_interface (extra_class)) {
2442 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2443 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2444 key [1] = remote_class->proxy_class;
2446 // Keep the list of interfaces sorted
2447 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2448 if (extra_class && remote_class->interfaces [i] > extra_class) {
2449 key [j++] = extra_class;
2452 key [j] = remote_class->interfaces [i];
2455 key [j] = extra_class;
2457 // Replace the old class. The interface list is the same
2458 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2459 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2460 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2461 for (i = 0; i < remote_class->interface_count; i++)
2462 key [2 + i] = remote_class->interfaces [i];
2470 * copy_remote_class_key:
2472 * Make a copy of KEY in the domain and return the copy.
2475 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2477 MONO_REQ_GC_NEUTRAL_MODE
2479 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2480 gpointer *mp_key = (gpointer *)mono_domain_alloc (domain, key_size);
2482 memcpy (mp_key, key, key_size);
2488 * mono_remote_class:
2489 * \param domain the application domain
2490 * \param class_name name of the remote class
2491 * \param error set on error
2492 * Creates and initializes a \c MonoRemoteClass object for a remote type.
2493 * On failure returns NULL and sets \p error
2496 mono_remote_class (MonoDomain *domain, MonoStringHandle class_name, MonoClass *proxy_class, MonoError *error)
2498 MONO_REQ_GC_UNSAFE_MODE;
2500 MonoRemoteClass *rc;
2501 gpointer* key, *mp_key;
2506 key = create_remote_class_key (NULL, proxy_class);
2508 mono_domain_lock (domain);
2509 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2513 mono_domain_unlock (domain);
2517 name = mono_string_to_utf8_mp (domain->mp, MONO_HANDLE_RAW (class_name), error);
2518 if (!is_ok (error)) {
2520 mono_domain_unlock (domain);
2524 mp_key = copy_remote_class_key (domain, key);
2528 if (mono_class_is_interface (proxy_class)) {
2529 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2530 rc->interface_count = 1;
2531 rc->interfaces [0] = proxy_class;
2532 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2534 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2535 rc->interface_count = 0;
2536 rc->proxy_class = proxy_class;
2539 rc->default_vtable = NULL;
2540 rc->xdomain_vtable = NULL;
2541 rc->proxy_class_name = name;
2542 #ifndef DISABLE_PERFCOUNTERS
2543 mono_perfcounters->loader_bytes += mono_string_length (MONO_HANDLE_RAW (class_name)) + 1;
2546 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2548 mono_domain_unlock (domain);
2553 * clone_remote_class:
2554 * Creates a copy of the remote_class, adding the provided class or interface
2556 static MonoRemoteClass*
2557 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2559 MONO_REQ_GC_NEUTRAL_MODE;
2561 MonoRemoteClass *rc;
2562 gpointer* key, *mp_key;
2564 key = create_remote_class_key (remote_class, extra_class);
2565 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2571 mp_key = copy_remote_class_key (domain, key);
2575 if (mono_class_is_interface (extra_class)) {
2577 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2578 rc->proxy_class = remote_class->proxy_class;
2579 rc->interface_count = remote_class->interface_count + 1;
2581 // Keep the list of interfaces sorted, since the hash key of
2582 // the remote class depends on this
2583 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2584 if (remote_class->interfaces [i] > extra_class && i == j)
2585 rc->interfaces [j++] = extra_class;
2586 rc->interfaces [j] = remote_class->interfaces [i];
2589 rc->interfaces [j] = extra_class;
2591 // Replace the old class. The interface array is the same
2592 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2593 rc->proxy_class = extra_class;
2594 rc->interface_count = remote_class->interface_count;
2595 if (rc->interface_count > 0)
2596 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2599 rc->default_vtable = NULL;
2600 rc->xdomain_vtable = NULL;
2601 rc->proxy_class_name = remote_class->proxy_class_name;
2603 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2609 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxyHandle rp, MonoError *error)
2611 MONO_REQ_GC_UNSAFE_MODE;
2615 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2616 mono_domain_lock (domain);
2617 gint32 target_domain_id = MONO_HANDLE_GETVAL (rp, target_domain_id);
2618 if (target_domain_id != -1) {
2619 if (remote_class->xdomain_vtable == NULL)
2620 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN, error);
2621 mono_domain_unlock (domain);
2622 mono_loader_unlock ();
2623 return_val_if_nok (error, NULL);
2624 return remote_class->xdomain_vtable;
2626 if (remote_class->default_vtable == NULL) {
2627 MonoReflectionTypeHandle reftype = MONO_HANDLE_NEW (MonoReflectionType, NULL);
2628 MONO_HANDLE_GET (reftype, rp, class_to_proxy);
2630 MonoType *type = MONO_HANDLE_GETVAL (reftype, type);
2631 MonoClass *klass = mono_class_from_mono_type (type);
2633 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)))
2634 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP, error);
2637 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN, error);
2638 /* N.B. both branches of the if modify error */
2639 if (!is_ok (error)) {
2640 mono_domain_unlock (domain);
2641 mono_loader_unlock ();
2646 mono_domain_unlock (domain);
2647 mono_loader_unlock ();
2648 return remote_class->default_vtable;
2652 * mono_upgrade_remote_class:
2653 * \param domain the application domain
2654 * \param tproxy the proxy whose remote class has to be upgraded.
2655 * \param klass class to which the remote class can be casted.
2656 * \param error set on error
2657 * Updates the vtable of the remote class by adding the necessary method slots
2658 * and interface offsets so it can be safely casted to klass. klass can be a
2659 * class or an interface. On success returns TRUE, on failure returns FALSE and sets \p error.
2662 mono_upgrade_remote_class (MonoDomain *domain, MonoObjectHandle proxy_object, MonoClass *klass, MonoError *error)
2664 MONO_REQ_GC_UNSAFE_MODE;
2668 MonoTransparentProxyHandle tproxy = MONO_HANDLE_CAST (MonoTransparentProxy, proxy_object);
2669 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (tproxy, remote_class);
2671 gboolean redo_vtable;
2672 if (mono_class_is_interface (klass)) {
2675 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2676 if (remote_class->interfaces [i] == klass)
2677 redo_vtable = FALSE;
2680 redo_vtable = (remote_class->proxy_class != klass);
2683 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2684 mono_domain_lock (domain);
2686 MonoRemoteClass *fresh_remote_class = clone_remote_class (domain, remote_class, klass);
2687 MONO_HANDLE_SETVAL (tproxy, remote_class, MonoRemoteClass*, fresh_remote_class);
2688 MonoRealProxyHandle real_proxy = MONO_HANDLE_NEW (MonoRealProxy, NULL);
2689 MONO_HANDLE_GET (real_proxy, tproxy, rp);
2690 MONO_HANDLE_SETVAL (proxy_object, vtable, MonoVTable*, mono_remote_class_vtable (domain, fresh_remote_class, real_proxy, error));
2696 mono_domain_unlock (domain);
2697 mono_loader_unlock ();
2698 return is_ok (error);
2700 #endif /* DISABLE_REMOTING */
2704 * mono_object_get_virtual_method:
2705 * \param obj object to operate on.
2706 * \param method method
2707 * Retrieves the \c MonoMethod that would be called on \p obj if \p obj is passed as
2708 * the instance of a callvirt of \p method.
2711 mono_object_get_virtual_method (MonoObject *obj_raw, MonoMethod *method)
2713 MONO_REQ_GC_UNSAFE_MODE;
2714 HANDLE_FUNCTION_ENTER ();
2716 MONO_HANDLE_DCL (MonoObject, obj);
2717 MonoMethod *result = mono_object_handle_get_virtual_method (obj, method, &error);
2718 mono_error_assert_ok (&error);
2719 HANDLE_FUNCTION_RETURN_VAL (result);
2723 * mono_object_handle_get_virtual_method:
2724 * \param obj object to operate on.
2725 * \param method method
2726 * Retrieves the \c MonoMethod that would be called on \p obj if \p obj is passed as
2727 * the instance of a callvirt of \p method.
2730 mono_object_handle_get_virtual_method (MonoObjectHandle obj, MonoMethod *method, MonoError *error)
2734 gboolean is_proxy = FALSE;
2735 MonoClass *klass = mono_handle_class (obj);
2736 if (mono_class_is_transparent_proxy (klass)) {
2737 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), remote_class);
2738 klass = remote_class->proxy_class;
2741 return class_get_virtual_method (klass, method, is_proxy, error);
2745 class_get_virtual_method (MonoClass *klass, MonoMethod *method, gboolean is_proxy, MonoError *error)
2750 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2753 mono_class_setup_vtable (klass);
2754 MonoMethod **vtable = klass->vtable;
2756 if (method->slot == -1) {
2757 /* method->slot might not be set for instances of generic methods */
2758 if (method->is_inflated) {
2759 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2760 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2763 g_assert_not_reached ();
2767 MonoMethod *res = NULL;
2768 /* check method->slot is a valid index: perform isinstance? */
2769 if (method->slot != -1) {
2770 if (mono_class_is_interface (method->klass)) {
2772 gboolean variance_used = FALSE;
2773 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2774 g_assert (iface_offset > 0);
2775 res = vtable [iface_offset + method->slot];
2778 res = vtable [method->slot];
2782 #ifndef DISABLE_REMOTING
2784 /* It may be an interface, abstract class method or generic method */
2785 if (!res || mono_method_signature (res)->generic_param_count)
2788 /* generic methods demand invoke_with_check */
2789 if (mono_method_signature (res)->generic_param_count)
2790 res = mono_marshal_get_remoting_invoke_with_check (res);
2793 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2794 res = mono_cominterop_get_invoke (res);
2797 res = mono_marshal_get_remoting_invoke (res);
2802 if (method->is_inflated) {
2803 /* Have to inflate the result */
2804 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, error);
2812 do_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2814 MONO_REQ_GC_UNSAFE_MODE;
2816 MonoObject *result = NULL;
2818 g_assert (callbacks.runtime_invoke);
2822 MONO_PROFILER_RAISE (method_begin_invoke, (method));
2824 result = callbacks.runtime_invoke (method, obj, params, exc, error);
2826 MONO_PROFILER_RAISE (method_end_invoke, (method));
2828 if (!mono_error_ok (error))
2835 * mono_runtime_invoke:
2836 * \param method method to invoke
2837 * \param obj object instance
2838 * \param params arguments to the method
2839 * \param exc exception information.
2840 * Invokes the method represented by \p method on the object \p obj.
2841 * \p obj is the \c this pointer, it should be NULL for static
2842 * methods, a \c MonoObject* for object instances and a pointer to
2843 * the value type for value types.
2845 * The params array contains the arguments to the method with the
2846 * same convention: \c MonoObject* pointers for object instances and
2847 * pointers to the value type otherwise.
2849 * From unmanaged code you'll usually use the
2850 * \c mono_runtime_invoke variant.
2852 * Note that this function doesn't handle virtual methods for
2853 * you, it will exec the exact method you pass: we still need to
2854 * expose a function to lookup the derived class implementation
2855 * of a virtual method (there are examples of this in the code,
2858 * You can pass NULL as the \p exc argument if you don't want to
2859 * catch exceptions, otherwise, \c *exc will be set to the exception
2860 * thrown, if any. if an exception is thrown, you can't use the
2861 * \c MonoObject* result from the function.
2863 * If the method returns a value type, it is boxed in an object
2867 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2872 res = mono_runtime_try_invoke (method, obj, params, exc, &error);
2873 if (*exc == NULL && !mono_error_ok(&error)) {
2874 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
2876 mono_error_cleanup (&error);
2878 res = mono_runtime_invoke_checked (method, obj, params, &error);
2879 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
2885 * mono_runtime_try_invoke:
2886 * \param method method to invoke
2887 * \param obj object instance
2888 * \param params arguments to the method
2889 * \param exc exception information.
2890 * \param error set on error
2891 * Invokes the method represented by \p method on the object \p obj.
2893 * \p obj is the \c this pointer, it should be NULL for static
2894 * methods, a \c MonoObject* for object instances and a pointer to
2895 * the value type for value types.
2897 * The params array contains the arguments to the method with the
2898 * same convention: \c MonoObject* pointers for object instances and
2899 * pointers to the value type otherwise.
2901 * From unmanaged code you'll usually use the
2902 * mono_runtime_invoke() variant.
2904 * Note that this function doesn't handle virtual methods for
2905 * you, it will exec the exact method you pass: we still need to
2906 * expose a function to lookup the derived class implementation
2907 * of a virtual method (there are examples of this in the code,
2910 * For this function, you must not pass NULL as the \p exc argument if
2911 * you don't want to catch exceptions, use
2912 * mono_runtime_invoke_checked(). If an exception is thrown, you
2913 * can't use the \c MonoObject* result from the function.
2915 * If this method cannot be invoked, \p error will be set and \p exc and
2916 * the return value must not be used.
2918 * If the method returns a value type, it is boxed in an object
2922 mono_runtime_try_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError* error)
2924 MONO_REQ_GC_UNSAFE_MODE;
2926 g_assert (exc != NULL);
2928 if (mono_runtime_get_no_exec ())
2929 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2931 return do_runtime_invoke (method, obj, params, exc, error);
2935 * mono_runtime_invoke_checked:
2936 * \param method method to invoke
2937 * \param obj object instance
2938 * \param params arguments to the method
2939 * \param error set on error
2940 * Invokes the method represented by \p method on the object \p obj.
2942 * \p obj is the \c this pointer, it should be NULL for static
2943 * methods, a \c MonoObject* for object instances and a pointer to
2944 * the value type for value types.
2946 * The \p params array contains the arguments to the method with the
2947 * same convention: \c MonoObject* pointers for object instances and
2948 * pointers to the value type otherwise.
2950 * From unmanaged code you'll usually use the
2951 * mono_runtime_invoke() variant.
2953 * Note that this function doesn't handle virtual methods for
2954 * you, it will exec the exact method you pass: we still need to
2955 * expose a function to lookup the derived class implementation
2956 * of a virtual method (there are examples of this in the code,
2959 * If an exception is thrown, you can't use the \c MonoObject* result
2960 * from the function.
2962 * If this method cannot be invoked, \p error will be set. If the
2963 * method throws an exception (and we're in coop mode) the exception
2964 * will be set in \p error.
2966 * If the method returns a value type, it is boxed in an object
2970 mono_runtime_invoke_checked (MonoMethod *method, void *obj, void **params, MonoError* error)
2972 MONO_REQ_GC_UNSAFE_MODE;
2974 if (mono_runtime_get_no_exec ())
2975 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2977 return do_runtime_invoke (method, obj, params, NULL, error);
2981 * mono_method_get_unmanaged_thunk:
2982 * \param method method to generate a thunk for.
2984 * Returns an \c unmanaged->managed thunk that can be used to call
2985 * a managed method directly from C.
2987 * The thunk's C signature closely matches the managed signature:
2989 * C#: <code>public bool Equals (object obj);</code>
2991 * C: <code>typedef MonoBoolean (*Equals)(MonoObject*, MonoObject*, MonoException**);</code>
2993 * The 1st (<code>this</code>) parameter must not be used with static methods:
2995 * C#: <code>public static bool ReferenceEquals (object a, object b);</code>
2997 * C: <code>typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*, MonoException**);</code>
2999 * The last argument must be a non-null \c MonoException* pointer.
3000 * It has "out" semantics. After invoking the thunk, \c *ex will be NULL if no
3001 * exception has been thrown in managed code. Otherwise it will point
3002 * to the \c MonoException* caught by the thunk. In this case, the result of
3003 * the thunk is undefined:
3006 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
3008 * MonoException *ex = NULL;
3010 * Equals func = mono_method_get_unmanaged_thunk (method);
3012 * MonoBoolean res = func (thisObj, objToCompare, &ex);
3016 * // handle exception
3021 * The calling convention of the thunk matches the platform's default
3022 * convention. This means that under Windows, C declarations must
3023 * contain the \c __stdcall attribute:
3025 * C: <code>typedef MonoBoolean (__stdcall *Equals)(MonoObject*, MonoObject*, MonoException**);</code>
3029 * Value type arguments and return values are treated as they were objects:
3031 * C#: <code>public static Rectangle Intersect (Rectangle a, Rectangle b);</code>
3032 * C: <code>typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);</code>
3034 * Arguments must be properly boxed upon trunk's invocation, while return
3035 * values must be unboxed.
3038 mono_method_get_unmanaged_thunk (MonoMethod *method)
3040 MONO_REQ_GC_NEUTRAL_MODE;
3041 MONO_REQ_API_ENTRYPOINT;
3046 g_assert (!mono_threads_is_coop_enabled ());
3048 MONO_ENTER_GC_UNSAFE;
3049 method = mono_marshal_get_thunk_invoke_wrapper (method);
3050 res = mono_compile_method_checked (method, &error);
3051 mono_error_cleanup (&error);
3052 MONO_EXIT_GC_UNSAFE;
3058 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
3060 MONO_REQ_GC_UNSAFE_MODE;
3064 /* object fields cannot be byref, so we don't need a
3066 gpointer *p = (gpointer*)dest;
3073 case MONO_TYPE_BOOLEAN:
3075 case MONO_TYPE_U1: {
3076 guint8 *p = (guint8*)dest;
3077 *p = value ? *(guint8*)value : 0;
3082 case MONO_TYPE_CHAR: {
3083 guint16 *p = (guint16*)dest;
3084 *p = value ? *(guint16*)value : 0;
3087 #if SIZEOF_VOID_P == 4
3092 case MONO_TYPE_U4: {
3093 gint32 *p = (gint32*)dest;
3094 *p = value ? *(gint32*)value : 0;
3097 #if SIZEOF_VOID_P == 8
3102 case MONO_TYPE_U8: {
3103 gint64 *p = (gint64*)dest;
3104 *p = value ? *(gint64*)value : 0;
3107 case MONO_TYPE_R4: {
3108 float *p = (float*)dest;
3109 *p = value ? *(float*)value : 0;
3112 case MONO_TYPE_R8: {
3113 double *p = (double*)dest;
3114 *p = value ? *(double*)value : 0;
3117 case MONO_TYPE_STRING:
3118 case MONO_TYPE_SZARRAY:
3119 case MONO_TYPE_CLASS:
3120 case MONO_TYPE_OBJECT:
3121 case MONO_TYPE_ARRAY:
3122 mono_gc_wbarrier_generic_store (dest, deref_pointer ? *(MonoObject **)value : (MonoObject *)value);
3124 case MONO_TYPE_FNPTR:
3125 case MONO_TYPE_PTR: {
3126 gpointer *p = (gpointer*)dest;
3127 *p = deref_pointer? *(gpointer*)value: value;
3130 case MONO_TYPE_VALUETYPE:
3131 /* note that 't' and 'type->type' can be different */
3132 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3133 t = mono_class_enum_basetype (type->data.klass)->type;
3136 MonoClass *klass = mono_class_from_mono_type (type);
3137 int size = mono_class_value_size (klass, NULL);
3139 mono_gc_bzero_atomic (dest, size);
3141 mono_gc_wbarrier_value_copy (dest, value, 1, klass);
3144 case MONO_TYPE_GENERICINST:
3145 t = type->data.generic_class->container_class->byval_arg.type;
3148 g_error ("got type %x", type->type);
3153 * mono_field_set_value:
3154 * \param obj Instance object
3155 * \param field \c MonoClassField describing the field to set
3156 * \param value The value to be set
3158 * Sets the value of the field described by \p field in the object instance \p obj
3159 * to the value passed in \p value. This method should only be used for instance
3160 * fields. For static fields, use \c mono_field_static_set_value.
3162 * The value must be in the native format of the field type.
3165 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3167 MONO_REQ_GC_UNSAFE_MODE;
3171 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3173 dest = (char*)obj + field->offset;
3174 mono_copy_value (field->type, dest, value, FALSE);
3178 * mono_field_static_set_value:
3179 * \param field \c MonoClassField describing the field to set
3180 * \param value The value to be set
3181 * Sets the value of the static field described by \p field
3182 * to the value passed in \p value.
3183 * The value must be in the native format of the field type.
3186 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3188 MONO_REQ_GC_UNSAFE_MODE;
3192 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3193 /* you cant set a constant! */
3194 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3196 if (field->offset == -1) {
3197 /* Special static */
3200 mono_domain_lock (vt->domain);
3201 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3202 mono_domain_unlock (vt->domain);
3203 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3205 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3207 mono_copy_value (field->type, dest, value, FALSE);
3211 * mono_vtable_get_static_field_data:
3213 * Internal use function: return a pointer to the memory holding the static fields
3214 * for a class or NULL if there are no static fields.
3215 * This is exported only for use by the debugger.
3218 mono_vtable_get_static_field_data (MonoVTable *vt)
3220 MONO_REQ_GC_NEUTRAL_MODE
3222 if (!vt->has_static_fields)
3224 return vt->vtable [vt->klass->vtable_size];
3228 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3230 MONO_REQ_GC_UNSAFE_MODE;
3234 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3235 if (field->offset == -1) {
3236 /* Special static */
3239 mono_domain_lock (vt->domain);
3240 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3241 mono_domain_unlock (vt->domain);
3242 src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3244 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3247 src = (guint8*)obj + field->offset;
3254 * mono_field_get_value:
3255 * \param obj Object instance
3256 * \param field \c MonoClassField describing the field to fetch information from
3257 * \param value pointer to the location where the value will be stored
3258 * Use this routine to get the value of the field \p field in the object
3261 * The pointer provided by value must be of the field type, for reference
3262 * types this is a \c MonoObject*, for value types its the actual pointer to
3270 * mono_field_get_value (obj, int_field, &i);
3274 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3276 MONO_REQ_GC_UNSAFE_MODE;
3282 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3284 src = (char*)obj + field->offset;
3285 mono_copy_value (field->type, value, src, TRUE);
3289 * mono_field_get_value_object:
3290 * \param domain domain where the object will be created (if boxing)
3291 * \param field \c MonoClassField describing the field to fetch information from
3292 * \param obj The object instance for the field.
3293 * \returns a new \c MonoObject with the value from the given field. If the
3294 * field represents a value type, the value is boxed.
3297 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3300 MonoObject* result = mono_field_get_value_object_checked (domain, field, obj, &error);
3301 mono_error_assert_ok (&error);
3306 * mono_field_get_value_object_checked:
3307 * \param domain domain where the object will be created (if boxing)
3308 * \param field \c MonoClassField describing the field to fetch information from
3309 * \param obj The object instance for the field.
3310 * \param error Set on error.
3311 * \returns a new \c MonoObject with the value from the given field. If the
3312 * field represents a value type, the value is boxed. On error returns NULL and sets \p error.
3315 mono_field_get_value_object_checked (MonoDomain *domain, MonoClassField *field, MonoObject *obj, MonoError *error)
3317 MONO_REQ_GC_UNSAFE_MODE;
3323 MonoVTable *vtable = NULL;
3325 gboolean is_static = FALSE;
3326 gboolean is_ref = FALSE;
3327 gboolean is_literal = FALSE;
3328 gboolean is_ptr = FALSE;
3329 MonoType *type = mono_field_get_type_checked (field, error);
3331 return_val_if_nok (error, NULL);
3333 switch (type->type) {
3334 case MONO_TYPE_STRING:
3335 case MONO_TYPE_OBJECT:
3336 case MONO_TYPE_CLASS:
3337 case MONO_TYPE_ARRAY:
3338 case MONO_TYPE_SZARRAY:
3343 case MONO_TYPE_BOOLEAN:
3346 case MONO_TYPE_CHAR:
3355 case MONO_TYPE_VALUETYPE:
3356 is_ref = type->byref;
3358 case MONO_TYPE_GENERICINST:
3359 is_ref = !mono_type_generic_inst_is_valuetype (type);
3365 g_error ("type 0x%x not handled in "
3366 "mono_field_get_value_object", type->type);
3370 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3373 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3377 vtable = mono_class_vtable_full (domain, field->parent, error);
3378 return_val_if_nok (error, NULL);
3380 if (!vtable->initialized) {
3381 mono_runtime_class_init_full (vtable, error);
3382 return_val_if_nok (error, NULL);
3391 get_default_field_value (domain, field, &o, error);
3392 return_val_if_nok (error, NULL);
3393 } else if (is_static) {
3394 mono_field_static_get_value_checked (vtable, field, &o, error);
3395 return_val_if_nok (error, NULL);
3397 mono_field_get_value (obj, field, &o);
3403 static MonoMethod *m;
3409 MonoClass *ptr_klass = mono_class_get_pointer_class ();
3410 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3416 get_default_field_value (domain, field, v, error);
3417 return_val_if_nok (error, NULL);
3418 } else if (is_static) {
3419 mono_field_static_get_value_checked (vtable, field, v, error);
3420 return_val_if_nok (error, NULL);
3422 mono_field_get_value (obj, field, v);
3425 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3426 args [0] = ptr ? *ptr : NULL;
3427 args [1] = mono_type_get_object_checked (mono_domain_get (), type, error);
3428 return_val_if_nok (error, NULL);
3430 o = mono_runtime_invoke_checked (m, NULL, args, error);
3431 return_val_if_nok (error, NULL);
3436 /* boxed value type */
3437 klass = mono_class_from_mono_type (type);
3439 if (mono_class_is_nullable (klass))
3440 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass, error);
3442 o = mono_object_new_checked (domain, klass, error);
3443 return_val_if_nok (error, NULL);
3444 v = ((gchar *) o) + sizeof (MonoObject);
3447 get_default_field_value (domain, field, v, error);
3448 return_val_if_nok (error, NULL);
3449 } else if (is_static) {
3450 mono_field_static_get_value_checked (vtable, field, v, error);
3451 return_val_if_nok (error, NULL);
3453 mono_field_get_value (obj, field, v);
3460 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value, MonoError *error)
3462 MONO_REQ_GC_UNSAFE_MODE;
3466 const char *p = blob;
3467 mono_metadata_decode_blob_size (p, &p);
3470 case MONO_TYPE_BOOLEAN:
3473 *(guint8 *) value = *p;
3475 case MONO_TYPE_CHAR:
3478 *(guint16*) value = read16 (p);
3482 *(guint32*) value = read32 (p);
3486 *(guint64*) value = read64 (p);
3489 readr4 (p, (float*) value);
3492 readr8 (p, (double*) value);
3494 case MONO_TYPE_STRING:
3495 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob, error);
3497 case MONO_TYPE_CLASS:
3498 *(gpointer*) value = NULL;
3502 g_warning ("type 0x%02x should not be in constant table", type);
3508 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error)
3510 MONO_REQ_GC_NEUTRAL_MODE;
3512 MonoTypeEnum def_type;
3517 data = mono_class_get_field_default_value (field, &def_type);
3518 mono_get_constant_value_from_blob (domain, def_type, data, value, error);
3522 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3524 MONO_REQ_GC_UNSAFE_MODE;
3530 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3532 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3533 get_default_field_value (vt->domain, field, value, error);
3537 if (field->offset == -1) {
3538 /* Special static */
3539 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3540 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3542 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3544 mono_copy_value (field->type, value, src, TRUE);
3548 * mono_field_static_get_value:
3549 * \param vt vtable to the object
3550 * \param field \c MonoClassField describing the field to fetch information from
3551 * \param value where the value is returned
3552 * Use this routine to get the value of the static field \p field value.
3554 * The pointer provided by value must be of the field type, for reference
3555 * types this is a \c MonoObject*, for value types its the actual pointer to
3563 * mono_field_static_get_value (vt, int_field, &i);
3567 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3569 MONO_REQ_GC_NEUTRAL_MODE;
3572 mono_field_static_get_value_checked (vt, field, value, &error);
3573 mono_error_cleanup (&error);
3577 * mono_field_static_get_value_checked:
3578 * \param vt vtable to the object
3579 * \param field \c MonoClassField describing the field to fetch information from
3580 * \param value where the value is returned
3581 * \param error set on error
3582 * Use this routine to get the value of the static field \p field value.
3584 * The pointer provided by value must be of the field type, for reference
3585 * types this is a \c MonoObject*, for value types its the actual pointer to
3590 * mono_field_static_get_value_checked (vt, int_field, &i, error);
3591 * if (!is_ok (error)) { ... }
3593 * On failure sets \p error.
3596 mono_field_static_get_value_checked (MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3598 MONO_REQ_GC_NEUTRAL_MODE;
3600 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value, error);
3604 * mono_property_set_value:
3605 * \param prop MonoProperty to set
3606 * \param obj instance object on which to act
3607 * \param params parameters to pass to the propery
3608 * \param exc optional exception
3609 * Invokes the property's set method with the given arguments on the
3610 * object instance obj (or NULL for static properties).
3612 * You can pass NULL as the exc argument if you don't want to
3613 * catch exceptions, otherwise, \c *exc will be set to the exception
3614 * thrown, if any. if an exception is thrown, you can't use the
3615 * \c MonoObject* result from the function.
3618 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3620 MONO_REQ_GC_UNSAFE_MODE;
3623 do_runtime_invoke (prop->set, obj, params, exc, &error);
3624 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3625 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3627 mono_error_cleanup (&error);
3632 * mono_property_set_value_checked:
3633 * \param prop \c MonoProperty to set
3634 * \param obj instance object on which to act
3635 * \param params parameters to pass to the propery
3636 * \param error set on error
3637 * Invokes the property's set method with the given arguments on the
3638 * object instance \p obj (or NULL for static properties).
3639 * \returns TRUE on success. On failure returns FALSE and sets \p error.
3640 * If an exception is thrown, it will be caught and returned via \p error.
3643 mono_property_set_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3645 MONO_REQ_GC_UNSAFE_MODE;
3650 do_runtime_invoke (prop->set, obj, params, &exc, error);
3651 if (exc != NULL && is_ok (error))
3652 mono_error_set_exception_instance (error, (MonoException*)exc);
3653 return is_ok (error);
3657 * mono_property_get_value:
3658 * \param prop \c MonoProperty to fetch
3659 * \param obj instance object on which to act
3660 * \param params parameters to pass to the propery
3661 * \param exc optional exception
3662 * Invokes the property's \c get method with the given arguments on the
3663 * object instance \p obj (or NULL for static properties).
3665 * You can pass NULL as the \p exc argument if you don't want to
3666 * catch exceptions, otherwise, \c *exc will be set to the exception
3667 * thrown, if any. if an exception is thrown, you can't use the
3668 * \c MonoObject* result from the function.
3670 * \returns the value from invoking the \c get method on the property.
3673 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3675 MONO_REQ_GC_UNSAFE_MODE;
3678 MonoObject *val = do_runtime_invoke (prop->get, obj, params, exc, &error);
3679 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3680 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3682 mono_error_cleanup (&error); /* FIXME don't raise here */
3689 * mono_property_get_value_checked:
3690 * \param prop \c MonoProperty to fetch
3691 * \param obj instance object on which to act
3692 * \param params parameters to pass to the propery
3693 * \param error set on error
3694 * Invokes the property's \c get method with the given arguments on the
3695 * object instance obj (or NULL for static properties).
3697 * If an exception is thrown, you can't use the
3698 * \c MonoObject* result from the function. The exception will be propagated via \p error.
3700 * \returns the value from invoking the get method on the property. On
3701 * failure returns NULL and sets \p error.
3704 mono_property_get_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3706 MONO_REQ_GC_UNSAFE_MODE;
3709 MonoObject *val = do_runtime_invoke (prop->get, obj, params, &exc, error);
3710 if (exc != NULL && !is_ok (error))
3711 mono_error_set_exception_instance (error, (MonoException*) exc);
3719 * mono_nullable_init:
3720 * @buf: The nullable structure to initialize.
3721 * @value: the value to initialize from
3722 * @klass: the type for the object
3724 * Initialize the nullable structure pointed to by @buf from @value which
3725 * should be a boxed value type. The size of @buf should be able to hold
3726 * as much data as the @klass->instance_size (which is the number of bytes
3727 * that will be copies).
3729 * Since Nullables have variable structure, we can not define a C
3730 * structure for them.
3733 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3735 MONO_REQ_GC_UNSAFE_MODE;
3737 MonoClass *param_class = klass->cast_class;
3739 mono_class_setup_fields (klass);
3740 g_assert (klass->fields_inited);
3742 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3743 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3745 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3747 if (param_class->has_references)
3748 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3750 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3752 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3757 * mono_nullable_init_from_handle:
3758 * @buf: The nullable structure to initialize.
3759 * @value: the value to initialize from
3760 * @klass: the type for the object
3762 * Initialize the nullable structure pointed to by @buf from @value which
3763 * should be a boxed value type. The size of @buf should be able to hold
3764 * as much data as the @klass->instance_size (which is the number of bytes
3765 * that will be copies).
3767 * Since Nullables have variable structure, we can not define a C
3768 * structure for them.
3771 mono_nullable_init_from_handle (guint8 *buf, MonoObjectHandle value, MonoClass *klass)
3773 MONO_REQ_GC_UNSAFE_MODE;
3775 MonoClass *param_class = klass->cast_class;
3777 mono_class_setup_fields (klass);
3778 g_assert (klass->fields_inited);
3780 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3781 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3783 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = MONO_HANDLE_IS_NULL (value) ? 0 : 1;
3784 if (!MONO_HANDLE_IS_NULL (value)) {
3785 uint32_t value_gchandle = 0;
3786 gpointer src = mono_object_handle_pin_unbox (value, &value_gchandle);
3787 if (param_class->has_references)
3788 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), src, 1, param_class);
3790 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), src, mono_class_value_size (param_class, NULL));
3791 mono_gchandle_free (value_gchandle);
3793 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3800 * mono_nullable_box:
3801 * \param buf The buffer representing the data to be boxed
3802 * \param klass the type to box it as.
3803 * \param error set on error
3805 * Creates a boxed vtype or NULL from the \c Nullable structure pointed to by
3806 * \p buf. On failure returns NULL and sets \p error.
3809 mono_nullable_box (guint8 *buf, MonoClass *klass, MonoError *error)
3811 MONO_REQ_GC_UNSAFE_MODE;
3814 MonoClass *param_class = klass->cast_class;
3816 mono_class_setup_fields (klass);
3817 g_assert (klass->fields_inited);
3819 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3820 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3822 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3823 MonoObject *o = mono_object_new_checked (mono_domain_get (), param_class, error);
3824 return_val_if_nok (error, NULL);
3825 if (param_class->has_references)
3826 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3828 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3836 * mono_get_delegate_invoke:
3837 * \param klass The delegate class
3838 * \returns the \c MonoMethod for the \c Invoke method in the delegate class or NULL if \p klass is a broken delegate type
3841 mono_get_delegate_invoke (MonoClass *klass)
3843 MONO_REQ_GC_NEUTRAL_MODE;
3847 /* This is called at runtime, so avoid the slower search in metadata */
3848 mono_class_setup_methods (klass);
3849 if (mono_class_has_failure (klass))
3851 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3856 * mono_get_delegate_begin_invoke:
3857 * \param klass The delegate class
3858 * \returns the \c MonoMethod for the \c BeginInvoke method in the delegate class or NULL if \p klass is a broken delegate type
3861 mono_get_delegate_begin_invoke (MonoClass *klass)
3863 MONO_REQ_GC_NEUTRAL_MODE;
3867 /* This is called at runtime, so avoid the slower search in metadata */
3868 mono_class_setup_methods (klass);
3869 if (mono_class_has_failure (klass))
3871 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3876 * mono_get_delegate_end_invoke:
3877 * \param klass The delegate class
3878 * \returns the \c MonoMethod for the \c EndInvoke method in the delegate class or NULL if \p klass is a broken delegate type
3881 mono_get_delegate_end_invoke (MonoClass *klass)
3883 MONO_REQ_GC_NEUTRAL_MODE;
3887 /* This is called at runtime, so avoid the slower search in metadata */
3888 mono_class_setup_methods (klass);
3889 if (mono_class_has_failure (klass))
3891 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3896 * mono_runtime_delegate_invoke:
3897 * \param delegate pointer to a delegate object.
3898 * \param params parameters for the delegate.
3899 * \param exc Pointer to the exception result.
3901 * Invokes the delegate method \p delegate with the parameters provided.
3903 * You can pass NULL as the \p exc argument if you don't want to
3904 * catch exceptions, otherwise, \c *exc will be set to the exception
3905 * thrown, if any. if an exception is thrown, you can't use the
3906 * \c MonoObject* result from the function.
3909 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3911 MONO_REQ_GC_UNSAFE_MODE;
3915 MonoObject *result = mono_runtime_delegate_try_invoke (delegate, params, exc, &error);
3917 mono_error_cleanup (&error);
3920 if (!is_ok (&error))
3921 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
3925 MonoObject *result = mono_runtime_delegate_invoke_checked (delegate, params, &error);
3926 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
3932 * mono_runtime_delegate_try_invoke:
3933 * \param delegate pointer to a delegate object.
3934 * \param params parameters for the delegate.
3935 * \param exc Pointer to the exception result.
3936 * \param error set on error
3937 * Invokes the delegate method \p delegate with the parameters provided.
3939 * You can pass NULL as the \p exc argument if you don't want to
3940 * catch exceptions, otherwise, \c *exc will be set to the exception
3941 * thrown, if any. On failure to execute, \p error will be set.
3942 * if an exception is thrown, you can't use the
3943 * \c MonoObject* result from the function.
3946 mono_runtime_delegate_try_invoke (MonoObject *delegate, void **params, MonoObject **exc, MonoError *error)
3948 MONO_REQ_GC_UNSAFE_MODE;
3952 MonoClass *klass = delegate->vtable->klass;
3955 im = mono_get_delegate_invoke (klass);
3957 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3960 o = mono_runtime_try_invoke (im, delegate, params, exc, error);
3962 o = mono_runtime_invoke_checked (im, delegate, params, error);
3969 * mono_runtime_delegate_invoke_checked:
3970 * \param delegate pointer to a delegate object.
3971 * \param params parameters for the delegate.
3972 * \param error set on error
3973 * Invokes the delegate method \p delegate with the parameters provided.
3974 * On failure \p error will be set and you can't use the \c MonoObject*
3975 * result from the function.
3978 mono_runtime_delegate_invoke_checked (MonoObject *delegate, void **params, MonoError *error)
3981 return mono_runtime_delegate_try_invoke (delegate, params, NULL, error);
3984 static char **main_args = NULL;
3985 static int num_main_args = 0;
3988 * mono_runtime_get_main_args:
3989 * \returns A \c MonoArray with the arguments passed to the main program
3992 mono_runtime_get_main_args (void)
3994 MONO_REQ_GC_UNSAFE_MODE;
3996 MonoArray *result = mono_runtime_get_main_args_checked (&error);
3997 mono_error_assert_ok (&error);
4002 * mono_runtime_get_main_args_checked:
4003 * \param error set on error
4004 * \returns a \c MonoArray with the arguments passed to the main
4005 * program. On failure returns NULL and sets \p error.
4008 mono_runtime_get_main_args_checked (MonoError *error)
4012 MonoDomain *domain = mono_domain_get ();
4016 res = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, num_main_args, error);
4017 return_val_if_nok (error, NULL);
4019 for (i = 0; i < num_main_args; ++i) {
4020 MonoString *arg = mono_string_new_checked (domain, main_args [i], error);
4021 return_val_if_nok (error, NULL);
4022 mono_array_setref (res, i, arg);
4029 free_main_args (void)
4031 MONO_REQ_GC_NEUTRAL_MODE;
4035 for (i = 0; i < num_main_args; ++i)
4036 g_free (main_args [i]);
4043 * mono_runtime_set_main_args:
4044 * \param argc number of arguments from the command line
4045 * \param argv array of strings from the command line
4046 * Set the command line arguments from an embedding application that doesn't otherwise call
4047 * \c mono_runtime_run_main.
4050 mono_runtime_set_main_args (int argc, char* argv[])
4052 MONO_REQ_GC_NEUTRAL_MODE;
4057 main_args = g_new0 (char*, argc);
4058 num_main_args = argc;
4060 for (i = 0; i < argc; ++i) {
4063 utf8_arg = mono_utf8_from_external (argv[i]);
4064 if (utf8_arg == NULL) {
4065 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
4066 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4070 main_args [i] = utf8_arg;
4077 * Prepare an array of arguments in order to execute a standard Main()
4078 * method (argc/argv contains the executable name). This method also
4079 * sets the command line argument value needed by System.Environment.
4083 prepare_run_main (MonoMethod *method, int argc, char *argv[])
4085 MONO_REQ_GC_UNSAFE_MODE;
4089 MonoArray *args = NULL;
4090 MonoDomain *domain = mono_domain_get ();
4091 gchar *utf8_fullpath;
4092 MonoMethodSignature *sig;
4094 g_assert (method != NULL);
4096 mono_thread_set_main (mono_thread_current ());
4098 main_args = g_new0 (char*, argc);
4099 num_main_args = argc;
4101 if (!g_path_is_absolute (argv [0])) {
4102 gchar *basename = g_path_get_basename (argv [0]);
4103 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
4107 utf8_fullpath = mono_utf8_from_external (fullpath);
4108 if(utf8_fullpath == NULL) {
4109 /* Printing the arg text will cause glib to
4110 * whinge about "Invalid UTF-8", but at least
4111 * its relevant, and shows the problem text
4114 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
4115 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4122 utf8_fullpath = mono_utf8_from_external (argv[0]);
4123 if(utf8_fullpath == NULL) {
4124 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
4125 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4130 main_args [0] = utf8_fullpath;
4132 for (i = 1; i < argc; ++i) {
4135 utf8_arg=mono_utf8_from_external (argv[i]);
4136 if(utf8_arg==NULL) {
4137 /* Ditto the comment about Invalid UTF-8 here */
4138 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
4139 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4143 main_args [i] = utf8_arg;
4148 sig = mono_method_signature (method);
4150 g_print ("Unable to load Main method.\n");
4154 if (sig->param_count) {
4155 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, argc, &error);
4156 mono_error_assert_ok (&error);
4157 for (i = 0; i < argc; ++i) {
4158 /* The encodings should all work, given that
4159 * we've checked all these args for the
4162 gchar *str = mono_utf8_from_external (argv [i]);
4163 MonoString *arg = mono_string_new_checked (domain, str, &error);
4164 mono_error_assert_ok (&error);
4165 mono_array_setref (args, i, arg);
4169 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, 0, &error);
4170 mono_error_assert_ok (&error);
4173 mono_assembly_set_main (method->klass->image->assembly);
4179 * mono_runtime_run_main:
4180 * \param method the method to start the application with (usually <code>Main</code>)
4181 * \param argc number of arguments from the command line
4182 * \param argv array of strings from the command line
4183 * \param exc excetption results
4184 * Execute a standard \c Main method (\p argc / \p argv contains the
4185 * executable name). This method also sets the command line argument value
4186 * needed by \c System.Environment.
4189 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
4192 MONO_REQ_GC_UNSAFE_MODE;
4195 MonoArray *args = prepare_run_main (method, argc, argv);
4198 res = mono_runtime_try_exec_main (method, args, exc);
4200 res = mono_runtime_exec_main_checked (method, args, &error);
4201 mono_error_raise_exception (&error); /* OK to throw, external only without a better alternative */
4207 * mono_runtime_run_main_checked:
4208 * \param method the method to start the application with (usually \c Main)
4209 * \param argc number of arguments from the command line
4210 * \param argv array of strings from the command line
4211 * \param error set on error
4213 * Execute a standard \c Main method (\p argc / \p argv contains the
4214 * executable name). This method also sets the command line argument value
4215 * needed by \c System.Environment. On failure sets \p error.
4218 mono_runtime_run_main_checked (MonoMethod *method, int argc, char* argv[],
4222 MonoArray *args = prepare_run_main (method, argc, argv);
4223 return mono_runtime_exec_main_checked (method, args, error);
4227 * mono_runtime_try_run_main:
4228 * \param method the method to start the application with (usually \c Main)
4229 * \param argc number of arguments from the command line
4230 * \param argv array of strings from the command line
4231 * \param exc set if \c Main throws an exception
4232 * \param error set if \c Main can't be executed
4233 * Execute a standard \c Main method (\p argc / \p argv contains the executable
4234 * name). This method also sets the command line argument value needed
4235 * by \c System.Environment. On failure sets \p error if Main can't be
4236 * executed or \p exc if it threw an exception.
4239 mono_runtime_try_run_main (MonoMethod *method, int argc, char* argv[],
4243 MonoArray *args = prepare_run_main (method, argc, argv);
4244 return mono_runtime_try_exec_main (method, args, exc);
4249 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4251 static MonoMethod *serialize_method;
4257 if (!serialize_method) {
4258 MonoClass *klass = mono_class_get_remoting_services_class ();
4259 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
4262 if (!serialize_method) {
4267 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
4272 array = mono_runtime_try_invoke (serialize_method, NULL, params, exc, &error);
4273 if (*exc == NULL && !mono_error_ok (&error))
4274 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert serialize_object to MonoError */
4276 mono_error_cleanup (&error);
4285 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4287 MONO_REQ_GC_UNSAFE_MODE;
4289 static MonoMethod *deserialize_method;
4295 if (!deserialize_method) {
4296 MonoClass *klass = mono_class_get_remoting_services_class ();
4297 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
4299 if (!deserialize_method) {
4307 result = mono_runtime_try_invoke (deserialize_method, NULL, params, exc, &error);
4308 if (*exc == NULL && !mono_error_ok (&error))
4309 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert deserialize_object to MonoError */
4311 mono_error_cleanup (&error);
4319 #ifndef DISABLE_REMOTING
4321 make_transparent_proxy (MonoObject *obj, MonoError *error)
4323 MONO_REQ_GC_UNSAFE_MODE;
4325 static MonoMethod *get_proxy_method;
4327 MonoDomain *domain = mono_domain_get ();
4328 MonoRealProxy *real_proxy;
4329 MonoReflectionType *reflection_type;
4330 MonoTransparentProxy *transparent_proxy;
4334 if (!get_proxy_method)
4335 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
4337 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
4339 real_proxy = (MonoRealProxy*) mono_object_new_checked (domain, mono_defaults.real_proxy_class, error);
4340 return_val_if_nok (error, NULL);
4341 reflection_type = mono_type_get_object_checked (domain, &obj->vtable->klass->byval_arg, error);
4342 return_val_if_nok (error, NULL);
4344 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
4345 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
4347 MonoObject *exc = NULL;
4349 transparent_proxy = (MonoTransparentProxy*) mono_runtime_try_invoke (get_proxy_method, real_proxy, NULL, &exc, error);
4350 if (exc != NULL && is_ok (error))
4351 mono_error_set_exception_instance (error, (MonoException*)exc);
4353 return (MonoObject*) transparent_proxy;
4355 #endif /* DISABLE_REMOTING */
4358 * mono_object_xdomain_representation
4359 * \param obj an object
4360 * \param target_domain a domain
4361 * \param error set on error.
4362 * Creates a representation of obj in the domain \p target_domain. This
4363 * is either a copy of \p obj arrived through via serialization and
4364 * deserialization or a proxy, depending on whether the object is
4365 * serializable or marshal by ref. \p obj must not be in \p target_domain.
4366 * If the object cannot be represented in \p target_domain, NULL is
4367 * returned and \p error is set appropriately.
4370 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoError *error)
4372 MONO_REQ_GC_UNSAFE_MODE;
4375 MonoObject *deserialized = NULL;
4377 #ifndef DISABLE_REMOTING
4378 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
4379 deserialized = make_transparent_proxy (obj, error);
4384 gboolean failure = FALSE;
4385 MonoDomain *domain = mono_domain_get ();
4386 MonoObject *serialized;
4387 MonoObject *exc = NULL;
4389 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
4390 serialized = serialize_object (obj, &failure, &exc);
4391 mono_domain_set_internal_with_options (target_domain, FALSE);
4393 deserialized = deserialize_object (serialized, &failure, &exc);
4394 if (domain != target_domain)
4395 mono_domain_set_internal_with_options (domain, FALSE);
4397 mono_error_set_exception_instance (error, (MonoException*)exc);
4400 return deserialized;
4403 /* Used in call_unhandled_exception_delegate */
4405 create_unhandled_exception_eventargs (MonoObject *exc, MonoError *error)
4407 MONO_REQ_GC_UNSAFE_MODE;
4412 MonoMethod *method = NULL;
4413 MonoBoolean is_terminating = TRUE;
4416 klass = mono_class_get_unhandled_exception_event_args_class ();
4417 mono_class_init (klass);
4419 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4420 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
4424 args [1] = &is_terminating;
4426 obj = mono_object_new_checked (mono_domain_get (), klass, error);
4427 return_val_if_nok (error, NULL);
4429 mono_runtime_invoke_checked (method, obj, args, error);
4430 return_val_if_nok (error, NULL);
4435 /* Used in mono_unhandled_exception */
4437 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4438 MONO_REQ_GC_UNSAFE_MODE;
4441 MonoObject *e = NULL;
4443 MonoDomain *current_domain = mono_domain_get ();
4445 if (domain != current_domain)
4446 mono_domain_set_internal_with_options (domain, FALSE);
4448 g_assert (domain == mono_object_domain (domain->domain));
4450 if (mono_object_domain (exc) != domain) {
4452 exc = mono_object_xdomain_representation (exc, domain, &error);
4454 if (!is_ok (&error)) {
4455 MonoError inner_error;
4456 MonoException *serialization_exc = mono_error_convert_to_exception (&error);
4457 exc = mono_object_xdomain_representation ((MonoObject*)serialization_exc, domain, &inner_error);
4458 mono_error_assert_ok (&inner_error);
4460 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4461 "System.Runtime.Serialization", "SerializationException",
4462 "Could not serialize unhandled exception.");
4466 g_assert (mono_object_domain (exc) == domain);
4468 pa [0] = domain->domain;
4469 pa [1] = create_unhandled_exception_eventargs (exc, &error);
4470 mono_error_assert_ok (&error);
4471 mono_runtime_delegate_try_invoke (delegate, pa, &e, &error);
4472 if (!is_ok (&error)) {
4474 e = (MonoObject*)mono_error_convert_to_exception (&error);
4476 mono_error_cleanup (&error);
4479 if (domain != current_domain)
4480 mono_domain_set_internal_with_options (current_domain, FALSE);
4483 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4484 if (!mono_error_ok (&error)) {
4485 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4486 mono_error_cleanup (&error);
4488 g_warning ("exception inside UnhandledException handler: %s\n", msg);
4494 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4497 * mono_runtime_unhandled_exception_policy_set:
4498 * \param policy the new policy
4499 * This is a VM internal routine.
4500 * Sets the runtime policy for handling unhandled exceptions.
4503 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4504 runtime_unhandled_exception_policy = policy;
4508 * mono_runtime_unhandled_exception_policy_get:
4510 * This is a VM internal routine.
4512 * Gets the runtime policy for handling unhandled exceptions.
4514 MonoRuntimeUnhandledExceptionPolicy
4515 mono_runtime_unhandled_exception_policy_get (void) {
4516 return runtime_unhandled_exception_policy;
4520 * mono_unhandled_exception:
4521 * \param exc exception thrown
4522 * This is a VM internal routine.
4524 * We call this function when we detect an unhandled exception
4525 * in the default domain.
4527 * It invokes the \c UnhandledException event in \c AppDomain or prints
4528 * a warning to the console
4531 mono_unhandled_exception (MonoObject *exc_raw)
4534 HANDLE_FUNCTION_ENTER ();
4535 MONO_HANDLE_DCL (MonoObject, exc);
4536 error_init (&error);
4537 mono_unhandled_exception_checked (exc, &error);
4538 mono_error_assert_ok (&error);
4539 HANDLE_FUNCTION_RETURN ();
4543 * mono_unhandled_exception:
4544 * @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 * UnhandledException event in AppDomain or prints
4552 * a warning to the console
4555 mono_unhandled_exception_checked (MonoObjectHandle exc, MonoError *error)
4557 MONO_REQ_GC_UNSAFE_MODE;
4560 MonoClassField *field;
4561 MonoDomain *current_domain, *root_domain;
4562 MonoObjectHandle current_appdomain_delegate = MONO_HANDLE_NEW (MonoObject, NULL);
4564 MonoClass *klass = mono_handle_class (exc);
4565 if (mono_class_has_parent (klass, mono_defaults.threadabortexception_class))
4568 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4571 current_domain = mono_domain_get ();
4572 root_domain = mono_get_root_domain ();
4574 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 */
4575 return_if_nok (error);
4576 if (current_domain != root_domain) {
4577 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 */
4578 return_if_nok (error);
4581 if (MONO_HANDLE_IS_NULL (current_appdomain_delegate) && MONO_HANDLE_IS_NULL (root_appdomain_delegate)) {
4582 mono_print_unhandled_exception (MONO_HANDLE_RAW (exc)); /* FIXME use handles for mono_print_unhandled_exception */
4584 /* unhandled exception callbacks must not be aborted */
4585 mono_threads_begin_abort_protected_block ();
4586 if (!MONO_HANDLE_IS_NULL (root_appdomain_delegate))
4587 call_unhandled_exception_delegate (root_domain, MONO_HANDLE_RAW (root_appdomain_delegate), MONO_HANDLE_RAW (exc)); /* FIXME use handles in call_unhandled_exception_delegate */
4588 if (!MONO_HANDLE_IS_NULL (current_appdomain_delegate))
4589 call_unhandled_exception_delegate (current_domain, MONO_HANDLE_RAW (current_appdomain_delegate), MONO_HANDLE_RAW (exc));
4590 mono_threads_end_abort_protected_block ();
4593 /* set exitcode only if we will abort the process */
4594 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4595 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4597 mono_environment_exitcode_set (1);
4602 * mono_runtime_exec_managed_code:
4603 * \param domain Application domain
4604 * \param main_func function to invoke from the execution thread
4605 * \param main_args parameter to the main_func
4606 * Launch a new thread to execute a function
4608 * \p main_func is called back from the thread with main_args as the
4609 * parameter. The callback function is expected to start \c Main
4610 * eventually. This function then waits for all managed threads to
4612 * It is not necessary anymore to execute managed code in a subthread,
4613 * so this function should not be used anymore by default: just
4614 * execute the code and then call mono_thread_manage().
4617 mono_runtime_exec_managed_code (MonoDomain *domain,
4618 MonoMainThreadFunc main_func,
4622 mono_thread_create_checked (domain, main_func, main_args, &error);
4623 mono_error_assert_ok (&error);
4625 mono_thread_manage ();
4629 prepare_thread_to_exec_main (MonoDomain *domain, MonoMethod *method)
4631 MonoInternalThread* thread = mono_thread_internal_current ();
4632 MonoCustomAttrInfo* cinfo;
4633 gboolean has_stathread_attribute;
4635 if (!domain->entry_assembly) {
4638 MonoAssembly *assembly;
4640 assembly = method->klass->image->assembly;
4641 domain->entry_assembly = assembly;
4642 /* Domains created from another domain already have application_base and configuration_file set */
4643 if (domain->setup->application_base == NULL) {
4644 MonoString *basedir = mono_string_new_checked (domain, assembly->basedir, &error);
4645 mono_error_assert_ok (&error);
4646 MONO_OBJECT_SETREF (domain->setup, application_base, basedir);
4649 if (domain->setup->configuration_file == NULL) {
4650 str = g_strconcat (assembly->image->name, ".config", NULL);
4651 MonoString *config_file = mono_string_new_checked (domain, str, &error);
4652 mono_error_assert_ok (&error);
4653 MONO_OBJECT_SETREF (domain->setup, configuration_file, config_file);
4655 mono_domain_set_options_from_config (domain);
4659 MonoError cattr_error;
4660 cinfo = mono_custom_attrs_from_method_checked (method, &cattr_error);
4661 mono_error_cleanup (&cattr_error); /* FIXME warn here? */
4663 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, mono_class_get_sta_thread_attribute_class ());
4665 mono_custom_attrs_free (cinfo);
4667 has_stathread_attribute = FALSE;
4669 if (has_stathread_attribute) {
4670 thread->apartment_state = ThreadApartmentState_STA;
4672 thread->apartment_state = ThreadApartmentState_MTA;
4674 mono_thread_init_apartment_state ();
4679 do_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4681 MONO_REQ_GC_UNSAFE_MODE;
4691 /* FIXME: check signature of method */
4692 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4694 res = mono_runtime_invoke_checked (method, NULL, pa, error);
4696 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4699 mono_environment_exitcode_set (rval);
4701 mono_runtime_invoke_checked (method, NULL, pa, error);
4713 do_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4715 MONO_REQ_GC_UNSAFE_MODE;
4725 /* FIXME: check signature of method */
4726 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4727 MonoError inner_error;
4729 res = mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4730 if (*exc == NULL && !mono_error_ok (&inner_error))
4731 *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4733 mono_error_cleanup (&inner_error);
4736 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4740 mono_environment_exitcode_set (rval);
4742 MonoError inner_error;
4743 mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4744 if (*exc == NULL && !mono_error_ok (&inner_error))
4745 *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4747 mono_error_cleanup (&inner_error);
4752 /* If the return type of Main is void, only
4753 * set the exitcode if an exception was thrown
4754 * (we don't want to blow away an
4755 * explicitly-set exit code)
4758 mono_environment_exitcode_set (rval);
4766 * Execute a standard Main() method (args doesn't contain the
4770 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4773 prepare_thread_to_exec_main (mono_object_domain (args), method);
4775 int rval = do_try_exec_main (method, args, exc);
4778 int rval = do_exec_main_checked (method, args, &error);
4779 mono_error_raise_exception (&error); /* OK to throw, external only with no better option */
4785 * Execute a standard Main() method (args doesn't contain the
4788 * On failure sets @error
4791 mono_runtime_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4794 prepare_thread_to_exec_main (mono_object_domain (args), method);
4795 return do_exec_main_checked (method, args, error);
4799 * Execute a standard Main() method (args doesn't contain the
4802 * On failure sets @error if Main couldn't be executed, or @exc if it threw an exception.
4805 mono_runtime_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4807 prepare_thread_to_exec_main (mono_object_domain (args), method);
4808 return do_try_exec_main (method, args, exc);
4813 /** invoke_array_extract_argument:
4814 * @params: array of arguments to the method.
4815 * @i: the index of the argument to extract.
4816 * @t: ith type from the method signature.
4817 * @has_byref_nullables: outarg - TRUE if method expects a byref nullable argument
4818 * @error: set on error.
4820 * Given an array of method arguments, return the ith one using the corresponding type
4821 * to perform necessary unboxing. If method expects a ref nullable argument, writes TRUE to @has_byref_nullables.
4823 * On failure sets @error and returns NULL.
4826 invoke_array_extract_argument (MonoArray *params, int i, MonoType *t, gboolean* has_byref_nullables, MonoError *error)
4828 MonoType *t_orig = t;
4829 gpointer result = NULL;
4835 case MONO_TYPE_BOOLEAN:
4838 case MONO_TYPE_CHAR:
4847 case MONO_TYPE_VALUETYPE:
4848 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (t_orig))) {
4849 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4850 result = mono_array_get (params, MonoObject*, i);
4852 *has_byref_nullables = TRUE;
4854 /* MS seems to create the objects if a null is passed in */
4855 gboolean was_null = FALSE;
4856 if (!mono_array_get (params, MonoObject*, i)) {
4857 MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (t_orig), error);
4858 return_val_if_nok (error, NULL);
4859 mono_array_setref (params, i, o);
4865 * We can't pass the unboxed vtype byref to the callee, since
4866 * that would mean the callee would be able to modify boxed
4867 * primitive types. So we (and MS) make a copy of the boxed
4868 * object, pass that to the callee, and replace the original
4869 * boxed object in the arg array with the copy.
4871 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4872 MonoObject *copy = mono_value_box_checked (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig), error);
4873 return_val_if_nok (error, NULL);
4874 mono_array_setref (params, i, copy);
4877 result = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4878 if (!t->byref && was_null)
4879 mono_array_setref (params, i, NULL);
4882 case MONO_TYPE_STRING:
4883 case MONO_TYPE_OBJECT:
4884 case MONO_TYPE_CLASS:
4885 case MONO_TYPE_ARRAY:
4886 case MONO_TYPE_SZARRAY:
4888 result = mono_array_addr (params, MonoObject*, i);
4889 // FIXME: I need to check this code path
4891 result = mono_array_get (params, MonoObject*, i);
4893 case MONO_TYPE_GENERICINST:
4895 t = &t->data.generic_class->container_class->this_arg;
4897 t = &t->data.generic_class->container_class->byval_arg;
4899 case MONO_TYPE_PTR: {
4902 /* The argument should be an IntPtr */
4903 arg = mono_array_get (params, MonoObject*, i);
4907 g_assert (arg->vtable->klass == mono_defaults.int_class);
4908 result = ((MonoIntPtr*)arg)->m_value;
4913 g_error ("type 0x%x not handled in mono_runtime_invoke_array", t_orig->type);
4918 * mono_runtime_invoke_array:
4919 * \param method method to invoke
4920 * \param obj object instance
4921 * \param params arguments to the method
4922 * \param exc exception information.
4923 * Invokes the method represented by \p method on the object \p obj.
4925 * \p obj is the \c this pointer, it should be NULL for static
4926 * methods, a \c MonoObject* for object instances and a pointer to
4927 * the value type for value types.
4929 * The \p params array contains the arguments to the method with the
4930 * same convention: \c MonoObject* pointers for object instances and
4931 * pointers to the value type otherwise. The \c _invoke_array
4932 * variant takes a C# \c object[] as the params argument (\c MonoArray*):
4933 * in this case the value types are boxed inside the
4934 * respective reference representation.
4936 * From unmanaged code you'll usually use the
4937 * mono_runtime_invoke_checked() variant.
4939 * Note that this function doesn't handle virtual methods for
4940 * you, it will exec the exact method you pass: we still need to
4941 * expose a function to lookup the derived class implementation
4942 * of a virtual method (there are examples of this in the code,
4945 * You can pass NULL as the \p exc argument if you don't want to
4946 * catch exceptions, otherwise, \c *exc will be set to the exception
4947 * thrown, if any. if an exception is thrown, you can't use the
4948 * \c MonoObject* result from the function.
4950 * If the method returns a value type, it is boxed in an object
4954 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4959 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, exc, &error);
4961 mono_error_cleanup (&error);
4964 if (!is_ok (&error))
4965 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
4969 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, NULL, &error);
4970 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
4976 * mono_runtime_invoke_array_checked:
4977 * \param method method to invoke
4978 * \param obj object instance
4979 * \param params arguments to the method
4980 * \param error set on failure.
4981 * Invokes the method represented by \p method on the object \p obj.
4983 * \p obj is the \c this pointer, it should be NULL for static
4984 * methods, a \c MonoObject* for object instances and a pointer to
4985 * the value type for value types.
4987 * The \p params array contains the arguments to the method with the
4988 * same convention: \c MonoObject* pointers for object instances and
4989 * pointers to the value type otherwise. The \c _invoke_array
4990 * variant takes a C# \c object[] as the \p params argument (\c MonoArray*):
4991 * in this case the value types are boxed inside the
4992 * respective reference representation.
4994 * From unmanaged code you'll usually use the
4995 * mono_runtime_invoke_checked() variant.
4997 * Note that this function doesn't handle virtual methods for
4998 * you, it will exec the exact method you pass: we still need to
4999 * expose a function to lookup the derived class implementation
5000 * of a virtual method (there are examples of this in the code,
5003 * On failure or exception, \p error will be set. In that case, you
5004 * can't use the \c MonoObject* result from the function.
5006 * If the method returns a value type, it is boxed in an object
5010 mono_runtime_invoke_array_checked (MonoMethod *method, void *obj, MonoArray *params,
5014 return mono_runtime_try_invoke_array (method, obj, params, NULL, error);
5018 * mono_runtime_try_invoke_array:
5019 * \param method method to invoke
5020 * \param obj object instance
5021 * \param params arguments to the method
5022 * \param exc exception information.
5023 * \param error set on failure.
5024 * Invokes the method represented by \p method on the object \p obj.
5026 * \p obj is the \c this pointer, it should be NULL for static
5027 * methods, a \c MonoObject* for object instances and a pointer to
5028 * the value type for value types.
5030 * The \p params array contains the arguments to the method with the
5031 * same convention: \c MonoObject* pointers for object instances and
5032 * pointers to the value type otherwise. The \c _invoke_array
5033 * variant takes a C# \c object[] as the params argument (\c MonoArray*):
5034 * in this case the value types are boxed inside the
5035 * respective reference representation.
5037 * From unmanaged code you'll usually use the
5038 * mono_runtime_invoke_checked() variant.
5040 * Note that this function doesn't handle virtual methods for
5041 * you, it will exec the exact method you pass: we still need to
5042 * expose a function to lookup the derived class implementation
5043 * of a virtual method (there are examples of this in the code,
5046 * You can pass NULL as the \p exc argument if you don't want to catch
5047 * exceptions, otherwise, \c *exc will be set to the exception thrown, if
5048 * any. On other failures, \p error will be set. If an exception is
5049 * thrown or there's an error, you can't use the \c MonoObject* result
5050 * from the function.
5052 * If the method returns a value type, it is boxed in an object
5056 mono_runtime_try_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
5057 MonoObject **exc, MonoError *error)
5059 MONO_REQ_GC_UNSAFE_MODE;
5063 MonoMethodSignature *sig = mono_method_signature (method);
5064 gpointer *pa = NULL;
5067 gboolean has_byref_nullables = FALSE;
5069 if (NULL != params) {
5070 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
5071 for (i = 0; i < mono_array_length (params); i++) {
5072 MonoType *t = sig->params [i];
5073 pa [i] = invoke_array_extract_argument (params, i, t, &has_byref_nullables, error);
5074 return_val_if_nok (error, NULL);
5078 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
5081 if (mono_class_is_nullable (method->klass)) {
5082 /* Need to create a boxed vtype instead */
5088 return mono_value_box_checked (mono_domain_get (), method->klass->cast_class, pa [0], error);
5093 obj = mono_object_new_checked (mono_domain_get (), method->klass, error);
5094 mono_error_assert_ok (error);
5095 g_assert (obj); /*maybe we should raise a TLE instead?*/
5096 #ifndef DISABLE_REMOTING
5097 if (mono_object_is_transparent_proxy (obj)) {
5098 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
5101 if (method->klass->valuetype)
5102 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
5105 } else if (method->klass->valuetype) {
5106 obj = mono_value_box_checked (mono_domain_get (), method->klass, obj, error);
5107 return_val_if_nok (error, NULL);
5111 mono_runtime_try_invoke (method, o, pa, exc, error);
5113 mono_runtime_invoke_checked (method, o, pa, error);
5116 return (MonoObject *)obj;
5118 if (mono_class_is_nullable (method->klass)) {
5119 MonoObject *nullable;
5121 /* Convert the unboxed vtype into a Nullable structure */
5122 nullable = mono_object_new_checked (mono_domain_get (), method->klass, error);
5123 return_val_if_nok (error, NULL);
5125 MonoObject *boxed = mono_value_box_checked (mono_domain_get (), method->klass->cast_class, obj, error);
5126 return_val_if_nok (error, NULL);
5127 mono_nullable_init ((guint8 *)mono_object_unbox (nullable), boxed, method->klass);
5128 obj = mono_object_unbox (nullable);
5131 /* obj must be already unboxed if needed */
5133 res = mono_runtime_try_invoke (method, obj, pa, exc, error);
5135 res = mono_runtime_invoke_checked (method, obj, pa, error);
5137 return_val_if_nok (error, NULL);
5139 if (sig->ret->type == MONO_TYPE_PTR) {
5140 MonoClass *pointer_class;
5141 static MonoMethod *box_method;
5143 MonoObject *box_exc;
5146 * The runtime-invoke wrapper returns a boxed IntPtr, need to
5147 * convert it to a Pointer object.
5149 pointer_class = mono_class_get_pointer_class ();
5151 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
5153 g_assert (res->vtable->klass == mono_defaults.int_class);
5154 box_args [0] = ((MonoIntPtr*)res)->m_value;
5155 box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, error);
5156 return_val_if_nok (error, NULL);
5158 res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, error);
5159 g_assert (box_exc == NULL);
5160 mono_error_assert_ok (error);
5163 if (has_byref_nullables) {
5165 * The runtime invoke wrapper already converted byref nullables back,
5166 * and stored them in pa, we just need to copy them back to the
5169 for (i = 0; i < mono_array_length (params); i++) {
5170 MonoType *t = sig->params [i];
5172 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
5173 mono_array_setref (params, i, pa [i]);
5183 * \param klass the class of the object that we want to create
5184 * \returns a newly created object whose definition is
5185 * looked up using \p klass. This will not invoke any constructors,
5186 * so the consumer of this routine has to invoke any constructors on
5187 * its own to initialize the object.
5189 * It returns NULL on failure.
5192 mono_object_new (MonoDomain *domain, MonoClass *klass)
5194 MONO_REQ_GC_UNSAFE_MODE;
5198 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5200 mono_error_cleanup (&error);
5205 ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
5207 MONO_REQ_GC_UNSAFE_MODE;
5211 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5213 mono_error_set_pending_exception (&error);
5218 * mono_object_new_checked:
5219 * \param klass the class of the object that we want to create
5220 * \param error set on error
5221 * \returns a newly created object whose definition is
5222 * looked up using \p klass. This will not invoke any constructors,
5223 * so the consumer of this routine has to invoke any constructors on
5224 * its own to initialize the object.
5226 * It returns NULL on failure and sets \p error.
5229 mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
5231 MONO_REQ_GC_UNSAFE_MODE;
5235 vtable = mono_class_vtable (domain, klass);
5236 g_assert (vtable); /* FIXME don't swallow the error */
5238 MonoObject *o = mono_object_new_specific_checked (vtable, error);
5243 * mono_object_new_pinned:
5245 * Same as mono_object_new, but the returned object will be pinned.
5246 * For SGEN, these objects will only be freed at appdomain unload.
5249 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
5251 MONO_REQ_GC_UNSAFE_MODE;
5257 vtable = mono_class_vtable (domain, klass);
5258 g_assert (vtable); /* FIXME don't swallow the error */
5260 MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
5262 if (G_UNLIKELY (!o))
5263 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
5264 else if (G_UNLIKELY (vtable->klass->has_finalize))
5265 mono_object_register_finalizer (o);
5271 * mono_object_new_specific:
5272 * \param vtable the vtable of the object that we want to create
5273 * \returns A newly created object with class and domain specified
5277 mono_object_new_specific (MonoVTable *vtable)
5280 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5281 mono_error_cleanup (&error);
5287 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
5289 MONO_REQ_GC_UNSAFE_MODE;
5295 /* check for is_com_object for COM Interop */
5296 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
5299 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
5302 MonoClass *klass = mono_class_get_activation_services_class ();
5305 mono_class_init (klass);
5307 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
5309 mono_error_set_not_supported (error, "Linked away.");
5312 vtable->domain->create_proxy_for_type_method = im;
5315 pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
5316 if (!mono_error_ok (error))
5319 o = mono_runtime_invoke_checked (im, NULL, pa, error);
5320 if (!mono_error_ok (error))
5327 return mono_object_new_alloc_specific_checked (vtable, error);
5331 ves_icall_object_new_specific (MonoVTable *vtable)
5334 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5335 mono_error_set_pending_exception (&error);
5341 * mono_object_new_alloc_specific:
5342 * \param vtable virtual table for the object.
5343 * This function allocates a new \c MonoObject with the type derived
5344 * from the \p vtable information. If the class of this object has a
5345 * finalizer, then the object will be tracked for finalization.
5347 * This method might raise an exception on errors. Use the
5348 * \c mono_object_new_fast_checked method if you want to manually raise
5351 * \returns the allocated object.
5354 mono_object_new_alloc_specific (MonoVTable *vtable)
5357 MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
5358 mono_error_cleanup (&error);
5364 * mono_object_new_alloc_specific_checked:
5365 * \param vtable virtual table for the object.
5366 * \param error holds the error return value.
5368 * This function allocates a new \c MonoObject with the type derived
5369 * from the \p vtable information. If the class of this object has a
5370 * finalizer, then the object will be tracked for finalization.
5372 * If there is not enough memory, the \p error parameter will be set
5373 * and will contain a user-visible message with the amount of bytes
5374 * that were requested.
5376 * \returns the allocated object, or NULL if there is not enough memory
5379 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
5381 MONO_REQ_GC_UNSAFE_MODE;
5387 o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5389 if (G_UNLIKELY (!o))
5390 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5391 else if (G_UNLIKELY (vtable->klass->has_finalize))
5392 mono_object_register_finalizer (o);
5398 * mono_object_new_fast:
5399 * \param vtable virtual table for the object.
5401 * This function allocates a new \c MonoObject with the type derived
5402 * from the \p vtable information. The returned object is not tracked
5403 * for finalization. If your object implements a finalizer, you should
5404 * use \c mono_object_new_alloc_specific instead.
5406 * This method might raise an exception on errors. Use the
5407 * \c mono_object_new_fast_checked method if you want to manually raise
5410 * \returns the allocated object.
5413 mono_object_new_fast (MonoVTable *vtable)
5416 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5417 mono_error_cleanup (&error);
5423 * mono_object_new_fast_checked:
5424 * \param vtable virtual table for the object.
5425 * \param error holds the error return value.
5427 * This function allocates a new \c MonoObject with the type derived
5428 * from the \p vtable information. The returned object is not tracked
5429 * for finalization. If your object implements a finalizer, you should
5430 * use \c mono_object_new_alloc_specific_checked instead.
5432 * If there is not enough memory, the \p error parameter will be set
5433 * and will contain a user-visible message with the amount of bytes
5434 * that were requested.
5436 * \returns the allocated object, or NULL if there is not enough memory
5439 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
5441 MONO_REQ_GC_UNSAFE_MODE;
5447 o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5449 if (G_UNLIKELY (!o))
5450 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5456 ves_icall_object_new_fast (MonoVTable *vtable)
5459 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5460 mono_error_set_pending_exception (&error);
5466 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
5468 MONO_REQ_GC_UNSAFE_MODE;
5474 o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
5476 if (G_UNLIKELY (!o))
5477 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5478 else if (G_UNLIKELY (vtable->klass->has_finalize))
5479 mono_object_register_finalizer (o);
5485 * mono_class_get_allocation_ftn:
5486 * \param vtable vtable
5487 * \param for_box the object will be used for boxing
5488 * \param pass_size_in_words Unused
5489 * \returns the allocation function appropriate for the given class.
5492 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
5494 MONO_REQ_GC_NEUTRAL_MODE;
5496 *pass_size_in_words = FALSE;
5498 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass))
5499 return ves_icall_object_new_specific;
5501 if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
5503 return ves_icall_object_new_fast;
5506 * FIXME: This is actually slower than ves_icall_object_new_fast, because
5507 * of the overhead of parameter passing.
5510 *pass_size_in_words = TRUE;
5511 #ifdef GC_REDIRECT_TO_LOCAL
5512 return GC_local_gcj_fast_malloc;
5514 return GC_gcj_fast_malloc;
5519 return ves_icall_object_new_specific;
5523 * mono_object_new_from_token:
5524 * \param image Context where the type_token is hosted
5525 * \param token a token of the type that we want to create
5526 * \returns A newly created object whose definition is
5527 * looked up using \p token in the \p image image
5530 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
5532 MONO_REQ_GC_UNSAFE_MODE;
5538 klass = mono_class_get_checked (image, token, &error);
5539 mono_error_assert_ok (&error);
5541 result = mono_object_new_checked (domain, klass, &error);
5543 mono_error_cleanup (&error);
5550 * mono_object_clone:
5551 * \param obj the object to clone
5552 * \returns A newly created object who is a shallow copy of \p obj
5555 mono_object_clone (MonoObject *obj)
5558 MonoObject *o = mono_object_clone_checked (obj, &error);
5559 mono_error_cleanup (&error);
5565 mono_object_clone_checked (MonoObject *obj, MonoError *error)
5567 MONO_REQ_GC_UNSAFE_MODE;
5574 size = obj->vtable->klass->instance_size;
5576 if (obj->vtable->klass->rank)
5577 return (MonoObject*)mono_array_clone_checked ((MonoArray*)obj, error);
5579 o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
5581 if (G_UNLIKELY (!o)) {
5582 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5586 /* If the object doesn't contain references this will do a simple memmove. */
5587 mono_gc_wbarrier_object_copy (o, obj);
5589 if (obj->vtable->klass->has_finalize)
5590 mono_object_register_finalizer (o);
5595 * mono_array_full_copy:
5596 * \param src source array to copy
5597 * \param dest destination array
5598 * Copies the content of one array to another with exactly the same type and size.
5601 mono_array_full_copy (MonoArray *src, MonoArray *dest)
5603 MONO_REQ_GC_UNSAFE_MODE;
5606 MonoClass *klass = src->obj.vtable->klass;
5608 g_assert (klass == dest->obj.vtable->klass);
5610 size = mono_array_length (src);
5611 g_assert (size == mono_array_length (dest));
5612 size *= mono_array_element_size (klass);
5614 array_full_copy_unchecked_size (src, dest, klass, size);
5618 array_full_copy_unchecked_size (MonoArray *src, MonoArray *dest, MonoClass *klass, uintptr_t size)
5620 if (mono_gc_is_moving ()) {
5621 if (klass->element_class->valuetype) {
5622 if (klass->element_class->has_references)
5623 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
5625 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5627 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
5630 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5635 * mono_array_clone_in_domain:
5636 * \param domain the domain in which the array will be cloned into
5637 * \param array the array to clone
5638 * \param error set on error
5639 * This routine returns a copy of the array that is hosted on the
5640 * specified \c MonoDomain. On failure returns NULL and sets \p error.
5643 mono_array_clone_in_domain (MonoDomain *domain, MonoArrayHandle array_handle, MonoError *error)
5645 MONO_REQ_GC_UNSAFE_MODE;
5647 MonoArrayHandle result = MONO_HANDLE_NEW (MonoArray, NULL);
5649 MonoClass *klass = mono_handle_class (array_handle);
5653 /* Pin source array here - if bounds is non-NULL, it's a pointer into the object data */
5654 uint32_t src_handle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, array_handle), TRUE);
5656 MonoArrayBounds *array_bounds = MONO_HANDLE_GETVAL (array_handle, bounds);
5658 if (array_bounds == NULL) {
5659 size = mono_array_handle_length (array_handle);
5660 o = mono_array_new_full_handle (domain, klass, &size, NULL, error);
5663 size *= mono_array_element_size (klass);
5665 uintptr_t *sizes = (uintptr_t *)alloca (klass->rank * sizeof (uintptr_t));
5666 intptr_t *lower_bounds = (intptr_t *)alloca (klass->rank * sizeof (intptr_t));
5667 size = mono_array_element_size (klass);
5668 for (int i = 0; i < klass->rank; ++i) {
5669 sizes [i] = array_bounds [i].length;
5670 size *= array_bounds [i].length;
5671 lower_bounds [i] = array_bounds [i].lower_bound;
5673 o = mono_array_new_full_handle (domain, klass, sizes, lower_bounds, error);
5678 uint32_t dst_handle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, o), TRUE);
5679 array_full_copy_unchecked_size (MONO_HANDLE_RAW (array_handle), MONO_HANDLE_RAW (o), klass, size);
5680 mono_gchandle_free (dst_handle);
5682 MONO_HANDLE_ASSIGN (result, o);
5685 mono_gchandle_free (src_handle);
5691 * \param array the array to clone
5692 * \returns A newly created array who is a shallow copy of \p array
5695 mono_array_clone (MonoArray *array)
5697 MONO_REQ_GC_UNSAFE_MODE;
5700 MonoArray *result = mono_array_clone_checked (array, &error);
5701 mono_error_cleanup (&error);
5706 * mono_array_clone_checked:
5707 * \param array the array to clone
5708 * \param error set on error
5709 * \returns A newly created array who is a shallow copy of \p array. On
5710 * failure returns NULL and sets \p error.
5713 mono_array_clone_checked (MonoArray *array_raw, MonoError *error)
5715 MONO_REQ_GC_UNSAFE_MODE;
5716 HANDLE_FUNCTION_ENTER ();
5717 /* FIXME: callers of mono_array_clone_checked should use handles */
5719 MONO_HANDLE_DCL (MonoArray, array);
5720 MonoArrayHandle result = mono_array_clone_in_domain (MONO_HANDLE_DOMAIN (array), array, error);
5721 HANDLE_FUNCTION_RETURN_OBJ (result);
5724 /* helper macros to check for overflow when calculating the size of arrays */
5725 #ifdef MONO_BIG_ARRAYS
5726 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
5727 #define MYGUINT_MAX MYGUINT64_MAX
5728 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5729 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
5730 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5731 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
5732 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
5734 #define MYGUINT32_MAX 4294967295U
5735 #define MYGUINT_MAX MYGUINT32_MAX
5736 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5737 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
5738 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5739 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
5740 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
5744 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
5746 MONO_REQ_GC_NEUTRAL_MODE;
5750 byte_len = mono_array_element_size (klass);
5751 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
5754 if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
5756 byte_len += MONO_SIZEOF_MONO_ARRAY;
5764 * mono_array_new_full:
5765 * \param domain domain where the object is created
5766 * \param array_class array class
5767 * \param lengths lengths for each dimension in the array
5768 * \param lower_bounds lower bounds for each dimension in the array (may be NULL)
5769 * This routine creates a new array object with the given dimensions,
5770 * lower bounds and type.
5773 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
5776 MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
5777 mono_error_cleanup (&error);
5783 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
5785 MONO_REQ_GC_UNSAFE_MODE;
5787 uintptr_t byte_len = 0, len, bounds_size;
5790 MonoArrayBounds *bounds;
5796 if (!array_class->inited)
5797 mono_class_init (array_class);
5801 /* A single dimensional array with a 0 lower bound is the same as an szarray */
5802 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
5804 if (len > MONO_ARRAY_MAX_INDEX) {
5805 mono_error_set_generic_error (error, "System", "OverflowException", "");
5810 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
5812 for (i = 0; i < array_class->rank; ++i) {
5813 if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
5814 mono_error_set_generic_error (error, "System", "OverflowException", "");
5817 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5818 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5825 if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5826 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5832 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5833 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5836 byte_len = (byte_len + 3) & ~3;
5837 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5838 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5841 byte_len += bounds_size;
5844 * Following three lines almost taken from mono_object_new ():
5845 * they need to be kept in sync.
5847 vtable = mono_class_vtable_full (domain, array_class, error);
5848 return_val_if_nok (error, NULL);
5851 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5853 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5855 if (G_UNLIKELY (!o)) {
5856 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5860 array = (MonoArray*)o;
5862 bounds = array->bounds;
5865 for (i = 0; i < array_class->rank; ++i) {
5866 bounds [i].length = lengths [i];
5868 bounds [i].lower_bound = lower_bounds [i];
5877 * \param domain domain where the object is created
5878 * \param eclass element class
5879 * \param n number of array elements
5880 * This routine creates a new szarray with \p n elements of type \p eclass.
5883 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5885 MONO_REQ_GC_UNSAFE_MODE;
5888 MonoArray *result = mono_array_new_checked (domain, eclass, n, &error);
5889 mono_error_cleanup (&error);
5894 * mono_array_new_checked:
5895 * \param domain domain where the object is created
5896 * \param eclass element class
5897 * \param n number of array elements
5898 * \param error set on error
5899 * This routine creates a new szarray with \p n elements of type \p eclass.
5900 * On failure returns NULL and sets \p error.
5903 mono_array_new_checked (MonoDomain *domain, MonoClass *eclass, uintptr_t n, MonoError *error)
5909 ac = mono_array_class_get (eclass, 1);
5912 MonoVTable *vtable = mono_class_vtable_full (domain, ac, error);
5913 return_val_if_nok (error, NULL);
5915 return mono_array_new_specific_checked (vtable, n, error);
5919 ves_icall_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5922 MonoArray *arr = mono_array_new_checked (domain, eclass, n, &error);
5923 mono_error_set_pending_exception (&error);
5929 * mono_array_new_specific:
5930 * \param vtable a vtable in the appropriate domain for an initialized class
5931 * \param n number of array elements
5932 * This routine is a fast alternative to \c mono_array_new for code which
5933 * can be sure about the domain it operates in.
5936 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5939 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5940 mono_error_cleanup (&error);
5946 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
5948 MONO_REQ_GC_UNSAFE_MODE;
5955 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
5956 mono_error_set_generic_error (error, "System", "OverflowException", "");
5960 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
5961 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5964 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
5966 if (G_UNLIKELY (!o)) {
5967 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5971 return (MonoArray*)o;
5975 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
5978 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5979 mono_error_set_pending_exception (&error);
5985 * mono_string_empty_wrapper:
5987 * Returns: The same empty string instance as the managed string.Empty
5990 mono_string_empty_wrapper (void)
5992 MonoDomain *domain = mono_domain_get ();
5993 return mono_string_empty (domain);
5997 * mono_string_empty:
5999 * Returns: The same empty string instance as the managed string.Empty
6002 mono_string_empty (MonoDomain *domain)
6005 g_assert (domain->empty_string);
6006 return domain->empty_string;
6010 * mono_string_new_utf16:
6011 * \param text a pointer to an utf16 string
6012 * \param len the length of the string
6013 * \returns A newly created string object which contains \p text.
6016 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
6018 MONO_REQ_GC_UNSAFE_MODE;
6021 MonoString *res = NULL;
6022 res = mono_string_new_utf16_checked (domain, text, len, &error);
6023 mono_error_cleanup (&error);
6029 * mono_string_new_utf16_checked:
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_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
6039 MONO_REQ_GC_UNSAFE_MODE;
6045 s = mono_string_new_size_checked (domain, len, error);
6047 memcpy (mono_string_chars (s), text, len * 2);
6053 * mono_string_new_utf16_handle:
6054 * \param text a pointer to an utf16 string
6055 * \param len the length of the string
6056 * \param error written on error.
6057 * \returns A newly created string object which contains \p text.
6058 * On error, returns NULL and sets \p error.
6061 mono_string_new_utf16_handle (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
6063 return MONO_HANDLE_NEW (MonoString, mono_string_new_utf16_checked (domain, text, len, error));
6067 * mono_string_new_utf32_checked:
6068 * \param text a pointer to an utf32 string
6069 * \param len the length of the string
6070 * \param error set on failure.
6071 * \returns A newly created string object which contains \p text. On failure returns NULL and sets \p error.
6074 mono_string_new_utf32_checked (MonoDomain *domain, const mono_unichar4 *text, gint32 len, MonoError *error)
6076 MONO_REQ_GC_UNSAFE_MODE;
6079 mono_unichar2 *utf16_output = NULL;
6080 gint32 utf16_len = 0;
6081 GError *gerror = NULL;
6082 glong items_written;
6085 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
6088 g_error_free (gerror);
6090 while (utf16_output [utf16_len]) utf16_len++;
6092 s = mono_string_new_size_checked (domain, utf16_len, error);
6093 return_val_if_nok (error, NULL);
6095 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
6097 g_free (utf16_output);
6103 * mono_string_new_utf32:
6104 * \param text a pointer to a UTF-32 string
6105 * \param len the length of the string
6106 * \returns A newly created string object which contains \p text.
6109 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
6112 MonoString *result = mono_string_new_utf32_checked (domain, text, len, &error);
6113 mono_error_cleanup (&error);
6118 * mono_string_new_size:
6119 * \param text a pointer to a UTF-16 string
6120 * \param len the length of the string
6121 * \returns A newly created string object of \p len
6124 mono_string_new_size (MonoDomain *domain, gint32 len)
6127 MonoString *str = mono_string_new_size_checked (domain, len, &error);
6128 mono_error_cleanup (&error);
6134 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
6136 MONO_REQ_GC_UNSAFE_MODE;
6144 /* check for overflow */
6145 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
6146 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
6150 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
6151 g_assert (size > 0);
6153 vtable = mono_class_vtable (domain, mono_defaults.string_class);
6156 s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
6158 if (G_UNLIKELY (!s)) {
6159 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", size);
6167 * mono_string_new_len:
6168 * \param text a pointer to an utf8 string
6169 * \param length number of bytes in \p text to consider
6170 * \returns A newly created string object which contains \p text.
6173 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
6175 MONO_REQ_GC_UNSAFE_MODE;
6178 MonoString *result = mono_string_new_len_checked (domain, text, length, &error);
6179 mono_error_cleanup (&error);
6184 * mono_string_new_len_checked:
6185 * \param text a pointer to an utf8 string
6186 * \param length number of bytes in \p text to consider
6187 * \param error set on error
6188 * \returns A newly created string object which contains \p text. On
6189 * failure returns NULL and sets \p error.
6192 mono_string_new_len_checked (MonoDomain *domain, const char *text, guint length, MonoError *error)
6194 MONO_REQ_GC_UNSAFE_MODE;
6198 GError *eg_error = NULL;
6199 MonoString *o = NULL;
6201 glong items_written;
6203 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
6206 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6208 g_error_free (eg_error);
6217 * \param text a pointer to a UTF-8 string
6218 * \deprecated Use \c mono_string_new_checked in new code.
6219 * This function asserts if it cannot allocate a new string.
6220 * \returns A newly created string object which contains \p text.
6223 mono_string_new (MonoDomain *domain, const char *text)
6226 MonoString *res = NULL;
6227 res = mono_string_new_checked (domain, text, &error);
6228 mono_error_assert_ok (&error);
6233 * mono_string_new_checked:
6234 * \param text a pointer to an utf8 string
6235 * \param merror set on error
6236 * \returns A newly created string object which contains \p text.
6237 * On error returns NULL and sets \p merror.
6240 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
6242 MONO_REQ_GC_UNSAFE_MODE;
6244 GError *eg_error = NULL;
6245 MonoString *o = NULL;
6247 glong items_written;
6254 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &eg_error);
6257 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6259 mono_error_set_execution_engine (error, "String conversion error: %s", eg_error->message);
6264 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
6269 MonoString *o = NULL;
6271 if (!g_utf8_validate (text, -1, &end)) {
6272 mono_error_set_argument (error, "text", "Not a valid utf8 string");
6276 len = g_utf8_strlen (text, -1);
6277 o = mono_string_new_size_checked (domain, len, error);
6280 str = mono_string_chars (o);
6282 while (text < end) {
6283 *str++ = g_utf8_get_char (text);
6284 text = g_utf8_next_char (text);
6293 * mono_string_new_wrapper:
6294 * \param text pointer to UTF-8 characters.
6295 * Helper function to create a string object from \p text in the current domain.
6298 mono_string_new_wrapper (const char *text)
6300 MONO_REQ_GC_UNSAFE_MODE;
6302 MonoDomain *domain = mono_domain_get ();
6306 MonoString *result = mono_string_new_checked (domain, text, &error);
6307 mono_error_assert_ok (&error);
6316 * \param class the class of the value
6317 * \param value a pointer to the unboxed data
6318 * \returns A newly created object which contains \p value.
6321 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
6324 MonoObject *result = mono_value_box_checked (domain, klass, value, &error);
6325 mono_error_cleanup (&error);
6330 * mono_value_box_checked:
6331 * \param domain the domain of the new object
6332 * \param class the class of the value
6333 * \param value a pointer to the unboxed data
6334 * \param error set on error
6335 * \returns A newly created object which contains \p value. On failure
6336 * returns NULL and sets \p error.
6339 mono_value_box_checked (MonoDomain *domain, MonoClass *klass, gpointer value, MonoError *error)
6341 MONO_REQ_GC_UNSAFE_MODE;
6348 g_assert (klass->valuetype);
6349 if (mono_class_is_nullable (klass))
6350 return mono_nullable_box ((guint8 *)value, klass, error);
6352 vtable = mono_class_vtable (domain, klass);
6355 size = mono_class_instance_size (klass);
6356 res = mono_object_new_alloc_specific_checked (vtable, error);
6357 return_val_if_nok (error, NULL);
6359 size = size - sizeof (MonoObject);
6361 if (mono_gc_is_moving ()) {
6362 g_assert (size == mono_class_value_size (klass, NULL));
6363 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
6365 #if NO_UNALIGNED_ACCESS
6366 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6370 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
6373 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
6376 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
6379 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
6382 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6386 if (klass->has_finalize) {
6387 mono_object_register_finalizer (res);
6388 return_val_if_nok (error, NULL);
6395 * \param dest destination pointer
6396 * \param src source pointer
6397 * \param klass a valuetype class
6398 * Copy a valuetype from \p src to \p dest. This function must be used
6399 * when \p klass contains reference fields.
6402 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
6404 MONO_REQ_GC_UNSAFE_MODE;
6406 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
6410 * mono_value_copy_array:
6411 * \param dest destination array
6412 * \param dest_idx index in the \p dest array
6413 * \param src source pointer
6414 * \param count number of items
6415 * Copy \p count valuetype items from \p src to the array \p dest at index \p dest_idx.
6416 * This function must be used when \p klass contains references fields.
6417 * Overlap is handled.
6420 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
6422 MONO_REQ_GC_UNSAFE_MODE;
6424 int size = mono_array_element_size (dest->obj.vtable->klass);
6425 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
6426 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
6427 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
6431 * mono_object_get_domain:
6432 * \param obj object to query
6433 * \returns the \c MonoDomain where the object is hosted
6436 mono_object_get_domain (MonoObject *obj)
6438 MONO_REQ_GC_UNSAFE_MODE;
6440 return mono_object_domain (obj);
6444 * mono_object_get_class:
6445 * \param obj object to query
6446 * Use this function to obtain the \c MonoClass* for a given \c MonoObject.
6447 * \returns the \c MonoClass of the object.
6450 mono_object_get_class (MonoObject *obj)
6452 MONO_REQ_GC_UNSAFE_MODE;
6454 return mono_object_class (obj);
6457 * mono_object_get_size:
6458 * \param o object to query
6459 * \returns the size, in bytes, of \p o
6462 mono_object_get_size (MonoObject* o)
6464 MONO_REQ_GC_UNSAFE_MODE;
6466 MonoClass* klass = mono_object_class (o);
6467 if (klass == mono_defaults.string_class) {
6468 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
6469 } else if (o->vtable->rank) {
6470 MonoArray *array = (MonoArray*)o;
6471 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
6472 if (array->bounds) {
6475 size += sizeof (MonoArrayBounds) * o->vtable->rank;
6479 return mono_class_instance_size (klass);
6484 * mono_object_unbox:
6485 * \param obj object to unbox
6486 * \returns a pointer to the start of the valuetype boxed in this
6489 * This method will assert if the object passed is not a valuetype.
6492 mono_object_unbox (MonoObject *obj)
6494 MONO_REQ_GC_UNSAFE_MODE;
6496 /* add assert for valuetypes? */
6497 g_assert (obj->vtable->klass->valuetype);
6498 return ((char*)obj) + sizeof (MonoObject);
6502 * mono_object_isinst:
6503 * \param obj an object
6504 * \param klass a pointer to a class
6505 * \returns \p obj if \p obj is derived from \p klass or NULL otherwise.
6508 mono_object_isinst (MonoObject *obj_raw, MonoClass *klass)
6510 MONO_REQ_GC_UNSAFE_MODE;
6512 HANDLE_FUNCTION_ENTER ();
6513 MONO_HANDLE_DCL (MonoObject, obj);
6515 MonoObjectHandle result = mono_object_handle_isinst (obj, klass, &error);
6516 mono_error_cleanup (&error);
6517 HANDLE_FUNCTION_RETURN_OBJ (result);
6522 * mono_object_isinst_checked:
6523 * \param obj an object
6524 * \param klass a pointer to a class
6525 * \param error set on error
6526 * \returns \p obj if \p obj is derived from \p klass or NULL if it isn't.
6527 * On failure returns NULL and sets \p error.
6530 mono_object_isinst_checked (MonoObject *obj_raw, MonoClass *klass, MonoError *error)
6532 MONO_REQ_GC_UNSAFE_MODE;
6534 HANDLE_FUNCTION_ENTER ();
6536 MONO_HANDLE_DCL (MonoObject, obj);
6537 MonoObjectHandle result = mono_object_handle_isinst (obj, klass, error);
6538 HANDLE_FUNCTION_RETURN_OBJ (result);
6542 * mono_object_handle_isinst:
6543 * \param obj an object
6544 * \param klass a pointer to a class
6545 * \param error set on error
6546 * \returns \p obj if \p obj is derived from \p klass or NULL if it isn't.
6547 * On failure returns NULL and sets \p error.
6550 mono_object_handle_isinst (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
6555 mono_class_init (klass);
6557 if (mono_class_is_marshalbyref (klass) || mono_class_is_interface (klass)) {
6558 return mono_object_handle_isinst_mbyref (obj, klass, error);
6561 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6563 if (!MONO_HANDLE_IS_NULL (obj) && mono_class_is_assignable_from (klass, mono_handle_class (obj)))
6564 MONO_HANDLE_ASSIGN (result, obj);
6569 * mono_object_isinst_mbyref:
6572 mono_object_isinst_mbyref (MonoObject *obj_raw, MonoClass *klass)
6574 MONO_REQ_GC_UNSAFE_MODE;
6576 HANDLE_FUNCTION_ENTER ();
6578 MONO_HANDLE_DCL (MonoObject, obj);
6579 MonoObjectHandle result = mono_object_handle_isinst_mbyref (obj, klass, &error);
6580 mono_error_cleanup (&error); /* FIXME better API that doesn't swallow the error */
6581 HANDLE_FUNCTION_RETURN_OBJ (result);
6585 mono_object_handle_isinst_mbyref (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
6589 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6591 if (MONO_HANDLE_IS_NULL (obj))
6594 MonoVTable *vt = MONO_HANDLE_GETVAL (obj, vtable);
6596 if (mono_class_is_interface (klass)) {
6597 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
6598 MONO_HANDLE_ASSIGN (result, obj);
6602 /* casting an array one of the invariant interfaces that must act as such */
6603 if (klass->is_array_special_interface) {
6604 if (mono_class_is_assignable_from (klass, vt->klass)) {
6605 MONO_HANDLE_ASSIGN (result, obj);
6610 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
6611 else if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, mono_handle_class (obj))) {
6612 MONO_HANDLE_ASSIGN (result, obj);
6616 MonoClass *oklass = vt->klass;
6617 if (mono_class_is_transparent_proxy (oklass)){
6618 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), remote_class);
6619 oklass = remote_class->proxy_class;
6622 mono_class_setup_supertypes (klass);
6623 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass)) {
6624 MONO_HANDLE_ASSIGN (result, obj);
6628 #ifndef DISABLE_REMOTING
6629 if (mono_class_is_transparent_proxy (vt->klass))
6631 MonoBoolean custom_type_info = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), custom_type_info);
6632 if (!custom_type_info)
6634 MonoDomain *domain = mono_domain_get ();
6635 MonoObjectHandle rp = MONO_HANDLE_NEW (MonoObject, NULL);
6636 MONO_HANDLE_GET (rp, MONO_HANDLE_CAST (MonoTransparentProxy, obj), rp);
6637 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
6638 MonoMethod *im = NULL;
6641 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
6643 mono_error_set_not_supported (error, "Linked away.");
6646 im = mono_object_handle_get_virtual_method (rp, im, error);
6651 MonoReflectionTypeHandle reftype = mono_type_get_object_handle (domain, &klass->byval_arg, error);
6655 pa [0] = MONO_HANDLE_RAW (reftype);
6656 pa [1] = MONO_HANDLE_RAW (obj);
6657 MonoObject *res = mono_runtime_invoke_checked (im, MONO_HANDLE_RAW (rp), pa, error);
6661 if (*(MonoBoolean *) mono_object_unbox(res)) {
6662 /* Update the vtable of the remote type, so it can safely cast to this new type */
6663 mono_upgrade_remote_class (domain, obj, klass, error);
6666 MONO_HANDLE_ASSIGN (result, obj);
6669 #endif /* DISABLE_REMOTING */
6675 * mono_object_castclass_mbyref:
6676 * \param obj an object
6677 * \param klass a pointer to a class
6678 * \returns \p obj if \p obj is derived from \p klass, returns NULL otherwise.
6681 mono_object_castclass_mbyref (MonoObject *obj_raw, MonoClass *klass)
6683 MONO_REQ_GC_UNSAFE_MODE;
6684 HANDLE_FUNCTION_ENTER ();
6686 MONO_HANDLE_DCL (MonoObject, obj);
6687 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6688 if (MONO_HANDLE_IS_NULL (obj))
6690 MONO_HANDLE_ASSIGN (result, mono_object_handle_isinst_mbyref (obj, klass, &error));
6691 mono_error_cleanup (&error);
6693 HANDLE_FUNCTION_RETURN_OBJ (result);
6697 MonoDomain *orig_domain;
6703 str_lookup (MonoDomain *domain, gpointer user_data)
6705 MONO_REQ_GC_UNSAFE_MODE;
6707 LDStrInfo *info = (LDStrInfo *)user_data;
6708 if (info->res || domain == info->orig_domain)
6710 info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
6714 mono_string_get_pinned (MonoString *str, MonoError *error)
6716 MONO_REQ_GC_UNSAFE_MODE;
6720 /* We only need to make a pinned version of a string if this is a moving GC */
6721 if (!mono_gc_is_moving ())
6725 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
6726 news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
6728 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
6729 news->length = mono_string_length (str);
6731 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6737 mono_string_is_interned_lookup (MonoString *str, int insert, MonoError *error)
6739 MONO_REQ_GC_UNSAFE_MODE;
6741 MonoGHashTable *ldstr_table;
6742 MonoString *s, *res;
6747 domain = ((MonoObject *)str)->vtable->domain;
6748 ldstr_table = domain->ldstr_table;
6750 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6756 /* Allocate outside the lock */
6758 s = mono_string_get_pinned (str, error);
6759 return_val_if_nok (error, NULL);
6762 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6767 mono_g_hash_table_insert (ldstr_table, s, s);
6772 LDStrInfo ldstr_info;
6773 ldstr_info.orig_domain = domain;
6774 ldstr_info.ins = str;
6775 ldstr_info.res = NULL;
6777 mono_domain_foreach (str_lookup, &ldstr_info);
6778 if (ldstr_info.res) {
6780 * the string was already interned in some other domain:
6781 * intern it in the current one as well.
6783 mono_g_hash_table_insert (ldstr_table, str, str);
6793 * mono_string_is_interned:
6794 * \param o String to probe
6795 * \returns Whether the string has been interned.
6798 mono_string_is_interned (MonoString *o)
6801 MonoString *result = mono_string_is_interned_lookup (o, FALSE, &error);
6802 /* This function does not fail. */
6803 mono_error_assert_ok (&error);
6808 * mono_string_intern:
6809 * \param o String to intern
6810 * Interns the string passed.
6811 * \returns The interned string.
6814 mono_string_intern (MonoString *str)
6817 MonoString *result = mono_string_intern_checked (str, &error);
6818 mono_error_assert_ok (&error);
6823 * mono_string_intern_checked:
6824 * \param o String to intern
6825 * \param error set on error.
6826 * Interns the string passed.
6827 * \returns The interned string. On failure returns NULL and sets \p error
6830 mono_string_intern_checked (MonoString *str, MonoError *error)
6832 MONO_REQ_GC_UNSAFE_MODE;
6836 return mono_string_is_interned_lookup (str, TRUE, error);
6841 * \param domain the domain where the string will be used.
6842 * \param image a metadata context
6843 * \param idx index into the user string table.
6844 * Implementation for the \c ldstr opcode.
6845 * \returns a loaded string from the \p image / \p idx combination.
6848 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
6851 MonoString *result = mono_ldstr_checked (domain, image, idx, &error);
6852 mono_error_cleanup (&error);
6857 * mono_ldstr_checked:
6858 * \param domain the domain where the string will be used.
6859 * \param image a metadata context
6860 * \param idx index into the user string table.
6861 * \param error set on error.
6862 * Implementation for the \c ldstr opcode.
6863 * \returns A loaded string from the \p image / \p idx combination.
6864 * On failure returns NULL and sets \p error.
6867 mono_ldstr_checked (MonoDomain *domain, MonoImage *image, guint32 idx, MonoError *error)
6869 MONO_REQ_GC_UNSAFE_MODE;
6872 if (image->dynamic) {
6873 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL, error);
6876 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6877 return NULL; /*FIXME we should probably be raising an exception here*/
6878 MonoString *str = mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx), error);
6884 * mono_ldstr_metadata_sig
6885 * \param domain the domain for the string
6886 * \param sig the signature of a metadata string
6887 * \param error set on error
6888 * \returns a \c MonoString for a string stored in the metadata. On
6889 * failure returns NULL and sets \p error.
6892 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error)
6894 MONO_REQ_GC_UNSAFE_MODE;
6897 const char *str = sig;
6898 MonoString *o, *interned;
6901 len2 = mono_metadata_decode_blob_size (str, &str);
6904 o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, error);
6905 return_val_if_nok (error, NULL);
6906 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
6909 guint16 *p2 = (guint16*)mono_string_chars (o);
6910 for (i = 0; i < len2; ++i) {
6911 *p2 = GUINT16_FROM_LE (*p2);
6917 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6920 return interned; /* o will get garbage collected */
6922 o = mono_string_get_pinned (o, error);
6925 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6927 mono_g_hash_table_insert (domain->ldstr_table, o, o);
6939 * Same as mono_ldstr, but return a NULL terminated utf8 string instead
6943 mono_ldstr_utf8 (MonoImage *image, guint32 idx, MonoError *error)
6949 GError *gerror = NULL;
6953 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6954 return NULL; /*FIXME we should probably be raising an exception here*/
6955 str = mono_metadata_user_string (image, idx);
6957 len2 = mono_metadata_decode_blob_size (str, &str);
6960 as = g_utf16_to_utf8 ((guint16*)str, len2, NULL, &written, &gerror);
6962 mono_error_set_argument (error, "string", "%s", gerror->message);
6963 g_error_free (gerror);
6966 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6967 if (len2 > written) {
6968 /* allocate the total length and copy the part of the string that has been converted */
6969 char *as2 = (char *)g_malloc0 (len2);
6970 memcpy (as2, as, written);
6979 * mono_string_to_utf8:
6980 * \param s a \c System.String
6981 * \deprecated Use \c mono_string_to_utf8_checked to avoid having an exception arbitrarily raised.
6982 * \returns the UTF-8 representation for \p s.
6983 * The resulting buffer needs to be freed with \c mono_free().
6986 mono_string_to_utf8 (MonoString *s)
6988 MONO_REQ_GC_UNSAFE_MODE;
6991 char *result = mono_string_to_utf8_checked (s, &error);
6993 if (!is_ok (&error)) {
6994 mono_error_cleanup (&error);
7001 * mono_string_to_utf8_checked:
7002 * \param s a \c System.String
7003 * \param error a \c MonoError.
7004 * Converts a \c MonoString to its UTF-8 representation. May fail; check
7005 * \p error to determine whether the conversion was successful.
7006 * The resulting buffer should be freed with \c mono_free().
7009 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
7011 MONO_REQ_GC_UNSAFE_MODE;
7015 GError *gerror = NULL;
7023 return g_strdup ("");
7025 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
7027 mono_error_set_argument (error, "string", "%s", gerror->message);
7028 g_error_free (gerror);
7031 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
7032 if (s->length > written) {
7033 /* allocate the total length and copy the part of the string that has been converted */
7034 char *as2 = (char *)g_malloc0 (s->length);
7035 memcpy (as2, as, written);
7044 mono_string_handle_to_utf8 (MonoStringHandle s, MonoError *error)
7046 return mono_string_to_utf8_checked (MONO_HANDLE_RAW (s), error);
7050 * mono_string_to_utf8_ignore:
7051 * \param s a MonoString
7052 * Converts a \c MonoString to its UTF-8 representation. Will ignore
7053 * invalid surrogate pairs.
7054 * The resulting buffer should be freed with \c mono_free().
7057 mono_string_to_utf8_ignore (MonoString *s)
7059 MONO_REQ_GC_UNSAFE_MODE;
7068 return g_strdup ("");
7070 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
7072 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
7073 if (s->length > written) {
7074 /* allocate the total length and copy the part of the string that has been converted */
7075 char *as2 = (char *)g_malloc0 (s->length);
7076 memcpy (as2, as, written);
7085 * mono_string_to_utf8_image_ignore:
7086 * \param s a \c System.String
7087 * Same as \c mono_string_to_utf8_ignore, but allocate the string from the image mempool.
7090 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
7092 MONO_REQ_GC_UNSAFE_MODE;
7094 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
7098 * mono_string_to_utf8_mp_ignore:
7099 * \param s a \c System.String
7100 * Same as \c mono_string_to_utf8_ignore, but allocate the string from a mempool.
7103 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
7105 MONO_REQ_GC_UNSAFE_MODE;
7107 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
7112 * mono_string_to_utf16:
7113 * \param s a \c MonoString
7114 * \returns a null-terminated array of the UTF-16 chars
7115 * contained in \p s. The result must be freed with \c g_free().
7116 * This is a temporary helper until our string implementation
7117 * is reworked to always include the null-terminating char.
7120 mono_string_to_utf16 (MonoString *s)
7122 MONO_REQ_GC_UNSAFE_MODE;
7129 as = (char *)g_malloc ((s->length * 2) + 2);
7130 as [(s->length * 2)] = '\0';
7131 as [(s->length * 2) + 1] = '\0';
7134 return (gunichar2 *)(as);
7137 memcpy (as, mono_string_chars(s), s->length * 2);
7138 return (gunichar2 *)(as);
7142 * mono_string_to_utf32:
7143 * \param s a \c MonoString
7144 * \returns a null-terminated array of the UTF-32 (UCS-4) chars
7145 * contained in \p s. The result must be freed with \c g_free().
7148 mono_string_to_utf32 (MonoString *s)
7150 MONO_REQ_GC_UNSAFE_MODE;
7152 mono_unichar4 *utf32_output = NULL;
7153 GError *error = NULL;
7154 glong items_written;
7159 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
7162 g_error_free (error);
7164 return utf32_output;
7168 * mono_string_from_utf16:
7169 * \param data the UTF-16 string (LPWSTR) to convert
7170 * Converts a NULL-terminated UTF-16 string (LPWSTR) to a \c MonoString.
7171 * \returns a \c MonoString.
7174 mono_string_from_utf16 (gunichar2 *data)
7177 MonoString *result = mono_string_from_utf16_checked (data, &error);
7178 mono_error_cleanup (&error);
7183 * mono_string_from_utf16_checked:
7184 * \param data the UTF-16 string (LPWSTR) to convert
7185 * \param error set on error
7186 * Converts a NULL-terminated UTF-16 string (LPWSTR) to a \c MonoString.
7187 * \returns a \c MonoString. On failure sets \p error and returns NULL.
7190 mono_string_from_utf16_checked (gunichar2 *data, MonoError *error)
7193 MONO_REQ_GC_UNSAFE_MODE;
7196 MonoDomain *domain = mono_domain_get ();
7202 while (data [len]) len++;
7204 return mono_string_new_utf16_checked (domain, data, len, error);
7208 * mono_string_from_utf32:
7209 * \param data the UTF-32 string (LPWSTR) to convert
7210 * Converts a UTF-32 (UCS-4) string to a \c MonoString.
7211 * \returns a \c MonoString.
7214 mono_string_from_utf32 (mono_unichar4 *data)
7217 MonoString *result = mono_string_from_utf32_checked (data, &error);
7218 mono_error_cleanup (&error);
7223 * mono_string_from_utf32_checked:
7224 * \param data the UTF-32 string (LPWSTR) to convert
7225 * \param error set on error
7226 * Converts a UTF-32 (UCS-4) string to a \c MonoString.
7227 * \returns a \c MonoString. On failure returns NULL and sets \p error.
7230 mono_string_from_utf32_checked (mono_unichar4 *data, MonoError *error)
7232 MONO_REQ_GC_UNSAFE_MODE;
7235 MonoString* result = NULL;
7236 mono_unichar2 *utf16_output = NULL;
7237 GError *gerror = NULL;
7238 glong items_written;
7244 while (data [len]) len++;
7246 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &gerror);
7249 g_error_free (gerror);
7251 result = mono_string_from_utf16_checked (utf16_output, error);
7252 g_free (utf16_output);
7257 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
7259 MONO_REQ_GC_UNSAFE_MODE;
7266 r = mono_string_to_utf8_ignore (s);
7268 r = mono_string_to_utf8_checked (s, error);
7269 if (!mono_error_ok (error))
7276 len = strlen (r) + 1;
7278 mp_s = (char *)mono_mempool_alloc (mp, len);
7280 mp_s = (char *)mono_image_alloc (image, len);
7282 memcpy (mp_s, r, len);
7290 * mono_string_to_utf8_image:
7291 * \param s a \c System.String
7292 * Same as \c mono_string_to_utf8, but allocate the string from the image mempool.
7295 mono_string_to_utf8_image (MonoImage *image, MonoStringHandle s, MonoError *error)
7297 MONO_REQ_GC_UNSAFE_MODE;
7299 return mono_string_to_utf8_internal (NULL, image, MONO_HANDLE_RAW (s), FALSE, error); /* FIXME pin the string */
7303 * mono_string_to_utf8_mp:
7304 * \param s a \c System.String
7305 * Same as \c mono_string_to_utf8, but allocate the string from a mempool.
7308 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
7310 MONO_REQ_GC_UNSAFE_MODE;
7312 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
7316 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
7319 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
7321 eh_callbacks = *cbs;
7324 MonoRuntimeExceptionHandlingCallbacks *
7325 mono_get_eh_callbacks (void)
7327 return &eh_callbacks;
7331 * mono_raise_exception:
7332 * \param ex exception object
7333 * Signal the runtime that the exception \p ex has been raised in unmanaged code.
7336 mono_raise_exception (MonoException *ex)
7338 MONO_REQ_GC_UNSAFE_MODE;
7341 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
7342 * that will cause gcc to omit the function epilog, causing problems when
7343 * the JIT tries to walk the stack, since the return address on the stack
7344 * will point into the next function in the executable, not this one.
7346 eh_callbacks.mono_raise_exception (ex);
7350 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
7352 MONO_REQ_GC_UNSAFE_MODE;
7354 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
7358 * mono_wait_handle_new:
7359 * \param domain Domain where the object will be created
7360 * \param handle Handle for the wait handle
7361 * \param error set on error.
7362 * \returns A new \c MonoWaitHandle created in the given domain for the
7363 * given handle. On failure returns NULL and sets \p error.
7366 mono_wait_handle_new (MonoDomain *domain, HANDLE handle, MonoError *error)
7368 MONO_REQ_GC_UNSAFE_MODE;
7370 MonoWaitHandle *res;
7371 gpointer params [1];
7372 static MonoMethod *handle_set;
7375 res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, error);
7376 return_val_if_nok (error, NULL);
7378 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
7380 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
7382 params [0] = &handle;
7384 mono_runtime_invoke_checked (handle_set, res, params, error);
7389 mono_wait_handle_get_handle (MonoWaitHandle *handle)
7391 MONO_REQ_GC_UNSAFE_MODE;
7393 static MonoClassField *f_safe_handle = NULL;
7396 if (!f_safe_handle) {
7397 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safeWaitHandle");
7398 g_assert (f_safe_handle);
7401 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
7407 mono_runtime_capture_context (MonoDomain *domain, MonoError *error)
7409 MONO_REQ_GC_UNSAFE_MODE;
7411 RuntimeInvokeFunction runtime_invoke;
7415 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
7416 MonoMethod *method = mono_get_context_capture_method ();
7417 MonoMethod *wrapper;
7420 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
7421 domain->capture_context_runtime_invoke = mono_compile_method_checked (wrapper, error);
7422 return_val_if_nok (error, NULL);
7423 domain->capture_context_method = mono_compile_method_checked (method, error);
7424 return_val_if_nok (error, NULL);
7427 runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
7429 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
7432 * mono_async_result_new:
7433 * \param domain domain where the object will be created.
7434 * \param handle wait handle.
7435 * \param state state to pass to AsyncResult
7436 * \param data C closure data.
7437 * \param error set on error.
7438 * Creates a new MonoAsyncResult (\c AsyncResult C# class) in the given domain.
7439 * If the handle is not null, the handle is initialized to a \c MonoWaitHandle.
7440 * On failure returns NULL and sets \p error.
7443 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data, MonoError *error)
7445 MONO_REQ_GC_UNSAFE_MODE;
7448 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, error);
7449 return_val_if_nok (error, NULL);
7450 MonoObject *context = mono_runtime_capture_context (domain, error);
7451 return_val_if_nok (error, NULL);
7452 /* we must capture the execution context from the original thread */
7454 MONO_OBJECT_SETREF (res, execution_context, context);
7455 /* note: result may be null if the flow is suppressed */
7458 res->data = (void **)data;
7459 MONO_OBJECT_SETREF (res, object_data, object_data);
7460 MONO_OBJECT_SETREF (res, async_state, state);
7461 MonoWaitHandle *wait_handle = mono_wait_handle_new (domain, handle, error);
7462 return_val_if_nok (error, NULL);
7464 MONO_OBJECT_SETREF (res, handle, (MonoObject *) wait_handle);
7466 res->sync_completed = FALSE;
7467 res->completed = FALSE;
7473 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
7475 MONO_REQ_GC_UNSAFE_MODE;
7482 g_assert (ares->async_delegate);
7484 ac = (MonoAsyncCall*) ares->object_data;
7486 res = mono_runtime_delegate_invoke_checked (ares->async_delegate, (void**) &ares->async_state, &error);
7487 if (mono_error_set_pending_exception (&error))
7490 gpointer wait_event = NULL;
7492 ac->msg->exc = NULL;
7494 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args, &error);
7496 /* The exit side of the invoke must not be aborted as it would leave the runtime in an undefined state */
7497 mono_threads_begin_abort_protected_block ();
7499 if (!ac->msg->exc) {
7500 MonoException *ex = mono_error_convert_to_exception (&error);
7501 ac->msg->exc = (MonoObject *)ex;
7503 mono_error_cleanup (&error);
7506 MONO_OBJECT_SETREF (ac, res, res);
7508 mono_monitor_enter ((MonoObject*) ares);
7509 ares->completed = 1;
7511 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
7512 mono_monitor_exit ((MonoObject*) ares);
7514 if (wait_event != NULL)
7515 mono_w32event_set (wait_event);
7517 error_init (&error); //the else branch would leave it in an undefined state
7519 mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
7521 mono_threads_end_abort_protected_block ();
7523 if (mono_error_set_pending_exception (&error))
7531 mono_message_init (MonoDomain *domain,
7532 MonoMethodMessage *this_obj,
7533 MonoReflectionMethod *method,
7534 MonoArray *out_args,
7537 MONO_REQ_GC_UNSAFE_MODE;
7539 static MonoMethod *init_message_method = NULL;
7541 if (!init_message_method) {
7542 init_message_method = mono_class_get_method_from_name (mono_defaults.mono_method_message_class, "InitMessage", 2);
7543 g_assert (init_message_method != NULL);
7547 /* FIXME set domain instead? */
7548 g_assert (domain == mono_domain_get ());
7555 mono_runtime_invoke_checked (init_message_method, this_obj, args, error);
7556 return is_ok (error);
7559 #ifndef DISABLE_REMOTING
7561 * mono_remoting_invoke:
7562 * \param real_proxy pointer to a \c RealProxy object
7563 * \param msg The \c MonoMethodMessage to execute
7564 * \param exc used to store exceptions
7565 * \param out_args used to store output arguments
7566 * This is used to call \c RealProxy::Invoke(). \c RealProxy::Invoke() returns an
7567 * \c IMessage interface and it is not trivial to extract results from there. So
7568 * we call an helper method \c PrivateInvoke instead of calling
7569 * \c RealProxy::Invoke() directly.
7570 * \returns the result object.
7573 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, MonoObject **exc, MonoArray **out_args, MonoError *error)
7575 MONO_REQ_GC_UNSAFE_MODE;
7578 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
7585 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
7588 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
7590 mono_error_set_not_supported (error, "Linked away.");
7593 real_proxy->vtable->domain->private_invoke_method = im;
7596 pa [0] = real_proxy;
7601 o = mono_runtime_try_invoke (im, NULL, pa, exc, error);
7602 return_val_if_nok (error, NULL);
7609 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
7610 MonoObject **exc, MonoArray **out_args, MonoError *error)
7612 MONO_REQ_GC_UNSAFE_MODE;
7614 static MonoClass *object_array_klass;
7619 MonoMethodSignature *sig;
7621 int i, j, outarg_count = 0;
7623 #ifndef DISABLE_REMOTING
7624 if (target && mono_object_is_transparent_proxy (target)) {
7625 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
7626 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7627 target = tp->rp->unwrapped_server;
7629 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args, error);
7634 domain = mono_domain_get ();
7635 method = msg->method->method;
7636 sig = mono_method_signature (method);
7638 for (i = 0; i < sig->param_count; i++) {
7639 if (sig->params [i]->byref)
7643 if (!object_array_klass) {
7646 klass = mono_array_class_get (mono_defaults.object_class, 1);
7649 mono_memory_barrier ();
7650 object_array_klass = klass;
7653 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, error);
7654 return_val_if_nok (error, NULL);
7656 mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
7659 MonoObject *ret = mono_runtime_try_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc, error);
7660 return_val_if_nok (error, NULL);
7662 for (i = 0, j = 0; i < sig->param_count; i++) {
7663 if (sig->params [i]->byref) {
7665 arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
7666 mono_array_setref (*out_args, j, arg);
7675 * prepare_to_string_method:
7677 * @target: Set to @obj or unboxed value if a valuetype
7679 * Returns: the ToString override for @obj. If @obj is a valuetype, @target is unboxed otherwise it's @obj.
7682 prepare_to_string_method (MonoObject *obj, void **target)
7684 MONO_REQ_GC_UNSAFE_MODE;
7686 static MonoMethod *to_string = NULL;
7694 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
7696 method = mono_object_get_virtual_method (obj, to_string);
7698 // Unbox value type if needed
7699 if (mono_class_is_valuetype (mono_method_get_class (method))) {
7700 *target = mono_object_unbox (obj);
7706 * mono_object_to_string:
7707 * \param obj The object
7708 * \param exc Any exception thrown by \c ToString. May be NULL.
7709 * \returns the result of calling \c ToString on an object.
7712 mono_object_to_string (MonoObject *obj, MonoObject **exc)
7715 MonoString *s = NULL;
7717 MonoMethod *method = prepare_to_string_method (obj, &target);
7719 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
7720 if (*exc == NULL && !mono_error_ok (&error))
7721 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
7723 mono_error_cleanup (&error);
7725 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
7726 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
7733 * mono_object_to_string_checked:
7734 * \param obj The object
7735 * \param error Set on error.
7736 * \returns the result of calling \c ToString() on an object. If the
7737 * method cannot be invoked or if it raises an exception, sets \p error
7741 mono_object_to_string_checked (MonoObject *obj, MonoError *error)
7745 MonoMethod *method = prepare_to_string_method (obj, &target);
7746 return (MonoString*) mono_runtime_invoke_checked (method, target, NULL, error);
7750 * mono_object_try_to_string:
7751 * \param obj The object
7752 * \param exc Any exception thrown by \c ToString(). Must not be NULL.
7753 * \param error Set if method cannot be invoked.
7754 * \returns the result of calling \c ToString() on an object. If the
7755 * method cannot be invoked sets \p error, if it raises an exception sets \p exc,
7759 mono_object_try_to_string (MonoObject *obj, MonoObject **exc, MonoError *error)
7764 MonoMethod *method = prepare_to_string_method (obj, &target);
7765 return (MonoString*) mono_runtime_try_invoke (method, target, NULL, exc, error);
7771 get_native_backtrace (MonoException *exc_raw)
7773 HANDLE_FUNCTION_ENTER ();
7774 MONO_HANDLE_DCL(MonoException, exc);
7775 char * trace = mono_exception_handle_get_native_backtrace (exc);
7776 HANDLE_FUNCTION_RETURN_VAL (trace);
7780 * mono_print_unhandled_exception:
7781 * \param exc The exception
7782 * Prints the unhandled exception.
7785 mono_print_unhandled_exception (MonoObject *exc)
7787 MONO_REQ_GC_UNSAFE_MODE;
7790 char *message = (char*)"";
7791 gboolean free_message = FALSE;
7794 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
7795 message = g_strdup ("OutOfMemoryException");
7796 free_message = TRUE;
7797 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
7798 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
7799 free_message = TRUE;
7802 if (((MonoException*)exc)->native_trace_ips) {
7803 message = get_native_backtrace ((MonoException*)exc);
7804 free_message = TRUE;
7806 MonoObject *other_exc = NULL;
7807 str = mono_object_try_to_string (exc, &other_exc, &error);
7808 if (other_exc == NULL && !is_ok (&error))
7809 other_exc = (MonoObject*)mono_error_convert_to_exception (&error);
7811 mono_error_cleanup (&error);
7813 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
7814 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
7816 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
7817 original_backtrace, nested_backtrace);
7819 g_free (original_backtrace);
7820 g_free (nested_backtrace);
7821 free_message = TRUE;
7823 message = mono_string_to_utf8_checked (str, &error);
7824 if (!mono_error_ok (&error)) {
7825 mono_error_cleanup (&error);
7826 message = (char *) "";
7828 free_message = TRUE;
7835 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
7836 * exc->vtable->klass->name, message);
7838 g_printerr ("\nUnhandled Exception:\n%s\n", message);
7845 * mono_delegate_ctor_with_method:
7846 * \param this pointer to an uninitialized delegate object
7847 * \param target target object
7848 * \param addr pointer to native code
7849 * \param method method
7850 * \param error set on error.
7851 * Initialize a delegate and sets a specific method, not the one
7852 * associated with \p addr. This is useful when sharing generic code.
7853 * In that case \p addr will most probably not be associated with the
7854 * correct instantiation of the method.
7855 * On failure returns FALSE and sets \p error.
7858 mono_delegate_ctor_with_method (MonoObjectHandle this_obj, MonoObjectHandle target, gpointer addr, MonoMethod *method, MonoError *error)
7860 MONO_REQ_GC_UNSAFE_MODE;
7863 MonoDelegateHandle delegate = MONO_HANDLE_CAST (MonoDelegate, this_obj);
7865 g_assert (!MONO_HANDLE_IS_NULL (this_obj));
7868 MonoClass *klass = mono_handle_class (this_obj);
7869 g_assert (mono_class_has_parent (klass, mono_defaults.multicastdelegate_class));
7872 MONO_HANDLE_SETVAL (delegate, method, MonoMethod*, method);
7874 mono_stats.delegate_creations++;
7876 #ifndef DISABLE_REMOTING
7877 if (!MONO_HANDLE_IS_NULL (target) && mono_class_is_transparent_proxy (mono_handle_class (target))) {
7879 method = mono_marshal_get_remoting_invoke (method);
7880 #ifdef ENABLE_INTERPRETER
7881 //g_error ("need RuntimeMethod in method_ptr when using interpreter");
7883 MONO_HANDLE_SETVAL (delegate, method_ptr, gpointer, mono_compile_method_checked (method, error));
7884 return_val_if_nok (error, FALSE);
7885 MONO_HANDLE_SET (delegate, target, target);
7889 MONO_HANDLE_SETVAL (delegate, method_ptr, gpointer, addr);
7890 MONO_HANDLE_SET (delegate, target, target);
7893 MONO_HANDLE_SETVAL (delegate, invoke_impl, gpointer, callbacks.create_delegate_trampoline (MONO_HANDLE_DOMAIN (delegate), mono_handle_class (delegate)));
7894 if (callbacks.init_delegate)
7895 callbacks.init_delegate (MONO_HANDLE_RAW (delegate)); /* FIXME: update init_delegate callback to take a MonoDelegateHandle */
7900 * mono_delegate_ctor:
7901 * \param this pointer to an uninitialized delegate object
7902 * \param target target object
7903 * \param addr pointer to native code
7904 * \param error set on error.
7905 * This is used to initialize a delegate.
7906 * On failure returns FALSE and sets \p error.
7909 mono_delegate_ctor (MonoObjectHandle this_obj, MonoObjectHandle target, gpointer addr, MonoError *error)
7911 MONO_REQ_GC_UNSAFE_MODE;
7914 MonoDomain *domain = mono_domain_get ();
7916 MonoMethod *method = NULL;
7920 ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
7922 if (!ji && domain != mono_get_root_domain ())
7923 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
7925 method = mono_jit_info_get_method (ji);
7926 g_assert (!mono_class_is_gtd (method->klass));
7929 return mono_delegate_ctor_with_method (this_obj, target, addr, method, error);
7933 * mono_method_call_message_new:
7934 * \param method method to encapsulate
7935 * \param params parameters to the method
7936 * \param invoke optional, delegate invoke.
7937 * \param cb async callback delegate.
7938 * \param state state passed to the async callback.
7939 * \param error set on error.
7940 * Translates arguments pointers into a \c MonoMethodMessage.
7941 * On failure returns NULL and sets \p error.
7944 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
7945 MonoDelegate **cb, MonoObject **state, MonoError *error)
7947 MONO_REQ_GC_UNSAFE_MODE;
7951 MonoDomain *domain = mono_domain_get ();
7952 MonoMethodSignature *sig = mono_method_signature (method);
7953 MonoMethodMessage *msg;
7956 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
7957 return_val_if_nok (error, NULL);
7960 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, error);
7961 return_val_if_nok (error, NULL);
7962 mono_message_init (domain, msg, rm, NULL, error);
7963 return_val_if_nok (error, NULL);
7964 count = sig->param_count - 2;
7966 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
7967 return_val_if_nok (error, NULL);
7968 mono_message_init (domain, msg, rm, NULL, error);
7969 return_val_if_nok (error, NULL);
7970 count = sig->param_count;
7973 for (i = 0; i < count; i++) {
7978 if (sig->params [i]->byref)
7979 vpos = *((gpointer *)params [i]);
7983 klass = mono_class_from_mono_type (sig->params [i]);
7985 if (klass->valuetype) {
7986 arg = mono_value_box_checked (domain, klass, vpos, error);
7987 return_val_if_nok (error, NULL);
7989 arg = *((MonoObject **)vpos);
7991 mono_array_setref (msg->args, i, arg);
7994 if (cb != NULL && state != NULL) {
7995 *cb = *((MonoDelegate **)params [i]);
7997 *state = *((MonoObject **)params [i]);
8004 * mono_method_return_message_restore:
8006 * Restore results from message based processing back to arguments pointers
8009 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args, MonoError *error)
8011 MONO_REQ_GC_UNSAFE_MODE;
8015 MonoMethodSignature *sig = mono_method_signature (method);
8016 int i, j, type, size, out_len;
8018 if (out_args == NULL)
8020 out_len = mono_array_length (out_args);
8024 for (i = 0, j = 0; i < sig->param_count; i++) {
8025 MonoType *pt = sig->params [i];
8030 mono_error_set_execution_engine (error, "The proxy call returned an incorrect number of output arguments");
8034 arg = (char *)mono_array_get (out_args, gpointer, j);
8037 g_assert (type != MONO_TYPE_VOID);
8039 if (MONO_TYPE_IS_REFERENCE (pt)) {
8040 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
8043 MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
8044 size = mono_class_value_size (klass, NULL);
8045 if (klass->has_references)
8046 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
8048 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
8050 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
8051 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
8060 #ifndef DISABLE_REMOTING
8063 * mono_load_remote_field:
8064 * \param this pointer to an object
8065 * \param klass klass of the object containing \p field
8066 * \param field the field to load
8067 * \param res a storage to store the result
8068 * This method is called by the runtime on attempts to load fields of
8069 * transparent proxy objects. \p this points to such TP, \p klass is the class of
8070 * the object containing \p field. \p res is a storage location which can be
8071 * used to store the result.
8072 * \returns an address pointing to the value of field.
8075 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
8078 gpointer result = mono_load_remote_field_checked (this_obj, klass, field, res, &error);
8079 mono_error_cleanup (&error);
8084 * mono_load_remote_field_checked:
8085 * \param this pointer to an object
8086 * \param klass klass of the object containing \p field
8087 * \param field the field to load
8088 * \param res a storage to store the result
8089 * \param error set on error
8090 * This method is called by the runtime on attempts to load fields of
8091 * transparent proxy objects. \p this points to such TP, \p klass is the class of
8092 * the object containing \p field. \p res is a storage location which can be
8093 * used to store the result.
8094 * \returns an address pointing to the value of field. On failure returns NULL and sets \p error.
8097 mono_load_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res, MonoError *error)
8099 MONO_REQ_GC_UNSAFE_MODE;
8101 static MonoMethod *getter = NULL;
8105 MonoDomain *domain = mono_domain_get ();
8106 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8107 MonoClass *field_class;
8108 MonoMethodMessage *msg;
8109 MonoArray *out_args;
8113 g_assert (mono_object_is_transparent_proxy (this_obj));
8114 g_assert (res != NULL);
8116 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8117 mono_field_get_value (tp->rp->unwrapped_server, field, res);
8122 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
8124 mono_error_set_not_supported (error, "Linked away.");
8129 field_class = mono_class_from_mono_type (field->type);
8131 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8132 return_val_if_nok (error, NULL);
8133 out_args = mono_array_new_checked (domain, mono_defaults.object_class, 1, error);
8134 return_val_if_nok (error, NULL);
8135 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, error);
8136 return_val_if_nok (error, NULL);
8137 mono_message_init (domain, msg, rm, out_args, error);
8138 return_val_if_nok (error, NULL);
8140 full_name = mono_type_get_full_name (klass);
8141 MonoString *full_name_str = mono_string_new_checked (domain, full_name, error);
8143 return_val_if_nok (error, NULL);
8144 mono_array_setref (msg->args, 0, full_name_str);
8145 MonoString *field_name = mono_string_new_checked (domain, mono_field_get_name (field), error);
8146 return_val_if_nok (error, NULL);
8147 mono_array_setref (msg->args, 1, field_name);
8149 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8150 return_val_if_nok (error, NULL);
8153 mono_error_set_exception_instance (error, (MonoException *)exc);
8157 if (mono_array_length (out_args) == 0)
8160 mono_gc_wbarrier_generic_store (res, mono_array_get (out_args, MonoObject *, 0));
8162 if (field_class->valuetype) {
8163 return ((char *)*res) + sizeof (MonoObject);
8169 * mono_load_remote_field_new:
8173 * Missing documentation.
8176 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
8180 MonoObject *result = mono_load_remote_field_new_checked (this_obj, klass, field, &error);
8181 mono_error_cleanup (&error);
8186 * mono_load_remote_field_new_checked:
8187 * \param this pointer to an object
8188 * \param klass klass of the object containing \p field
8189 * \param field the field to load
8190 * \param error set on error.
8191 * This method is called by the runtime on attempts to load fields of
8192 * transparent proxy objects. \p this points to such TP, \p klass is the class of
8193 * the object containing \p field.
8194 * \returns a freshly allocated object containing the value of the field. On failure returns NULL and sets \p error.
8197 mono_load_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoError *error)
8199 MONO_REQ_GC_UNSAFE_MODE;
8203 static MonoMethod *tp_load = NULL;
8205 g_assert (mono_object_is_transparent_proxy (this_obj));
8208 tp_load = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "LoadRemoteFieldNew", -1);
8210 mono_error_set_not_supported (error, "Linked away.");
8215 /* MonoType *type = mono_class_get_type (klass); */
8221 return mono_runtime_invoke_checked (tp_load, this_obj, args, error);
8225 * mono_store_remote_field:
8226 * \param this_obj pointer to an object
8227 * \param klass klass of the object containing \p field
8228 * \param field the field to load
8229 * \param val the value/object to store
8230 * This method is called by the runtime on attempts to store fields of
8231 * transparent proxy objects. \p this_obj points to such TP, \p klass is the class of
8232 * the object containing \p field. \p val is the new value to store in \p field.
8235 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
8238 (void) mono_store_remote_field_checked (this_obj, klass, field, val, &error);
8239 mono_error_cleanup (&error);
8243 * mono_store_remote_field_checked:
8244 * \param this_obj pointer to an object
8245 * \param klass klass of the object containing \p field
8246 * \param field the field to load
8247 * \param val the value/object to store
8248 * \param error set on error
8249 * This method is called by the runtime on attempts to store fields of
8250 * transparent proxy objects. \p this_obj points to such TP, \p klass is the class of
8251 * the object containing \p field. \p val is the new value to store in \p field.
8252 * \returns on success returns TRUE, on failure returns FALSE and sets \p error.
8255 mono_store_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val, MonoError *error)
8258 MONO_REQ_GC_UNSAFE_MODE;
8262 MonoDomain *domain = mono_domain_get ();
8263 MonoClass *field_class;
8266 g_assert (mono_object_is_transparent_proxy (this_obj));
8268 field_class = mono_class_from_mono_type (field->type);
8270 if (field_class->valuetype) {
8271 arg = mono_value_box_checked (domain, field_class, val, error);
8272 return_val_if_nok (error, FALSE);
8274 arg = *((MonoObject**)val);
8277 return mono_store_remote_field_new_checked (this_obj, klass, field, arg, error);
8281 * mono_store_remote_field_new:
8286 * Missing documentation
8289 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
8292 (void) mono_store_remote_field_new_checked (this_obj, klass, field, arg, &error);
8293 mono_error_cleanup (&error);
8297 * mono_store_remote_field_new_checked:
8303 * Missing documentation
8306 mono_store_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg, MonoError *error)
8308 MONO_REQ_GC_UNSAFE_MODE;
8310 static MonoMethod *tp_store = NULL;
8314 g_assert (mono_object_is_transparent_proxy (this_obj));
8317 tp_store = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "StoreRemoteField", -1);
8319 mono_error_set_not_supported (error, "Linked away.");
8329 mono_runtime_invoke_checked (tp_store, this_obj, args, error);
8330 return is_ok (error);
8335 * mono_create_ftnptr:
8337 * Given a function address, create a function descriptor for it.
8338 * This is only needed on some platforms.
8341 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
8343 return callbacks.create_ftnptr (domain, addr);
8347 * mono_get_addr_from_ftnptr:
8349 * Given a pointer to a function descriptor, return the function address.
8350 * This is only needed on some platforms.
8353 mono_get_addr_from_ftnptr (gpointer descr)
8355 return callbacks.get_addr_from_ftnptr (descr);
8359 * mono_string_chars:
8360 * \param s a \c MonoString
8361 * \returns a pointer to the UTF-16 characters stored in the \c MonoString
8364 mono_string_chars (MonoString *s)
8366 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
8372 * mono_string_length:
8373 * \param s MonoString
8374 * \returns the length in characters of the string
8377 mono_string_length (MonoString *s)
8379 MONO_REQ_GC_UNSAFE_MODE;
8385 * mono_string_handle_length:
8386 * \param s \c MonoString
8387 * \returns the length in characters of the string
8390 mono_string_handle_length (MonoStringHandle s)
8392 MONO_REQ_GC_UNSAFE_MODE;
8394 return MONO_HANDLE_GETVAL (s, length);
8399 * mono_array_length:
8400 * \param array a \c MonoArray*
8401 * \returns the total number of elements in the array. This works for
8402 * both vectors and multidimensional arrays.
8405 mono_array_length (MonoArray *array)
8407 MONO_REQ_GC_UNSAFE_MODE;
8409 return array->max_length;
8413 * mono_array_addr_with_size:
8414 * \param array a \c MonoArray*
8415 * \param size size of the array elements
8416 * \param idx index into the array
8417 * Use this function to obtain the address for the \p idx item on the
8418 * \p array containing elements of size \p size.
8420 * This method performs no bounds checking or type checking.
8421 * \returns the address of the \p idx element in the array.
8424 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
8426 MONO_REQ_GC_UNSAFE_MODE;
8428 return ((char*)(array)->vector) + size * idx;
8433 mono_glist_to_array (GList *list, MonoClass *eclass, MonoError *error)
8435 MonoDomain *domain = mono_domain_get ();
8443 len = g_list_length (list);
8444 res = mono_array_new_checked (domain, eclass, len, error);
8445 return_val_if_nok (error, NULL);
8447 for (i = 0; list; list = list->next, i++)
8448 mono_array_set (res, gpointer, i, list->data);
8455 * The following section is purely to declare prototypes and
8456 * document the API, as these C files are processed by our
8462 * \param array array to alter
8463 * \param element_type A C type name, this macro will use the sizeof(type) to determine the element size
8464 * \param index index into the array
8465 * \param value value to set
8466 * Value Type version: This sets the \p index's element of the \p array
8467 * with elements of size sizeof(type) to the provided \p value.
8469 * This macro does not attempt to perform type checking or bounds checking.
8471 * Use this to set value types in a \c MonoArray.
8473 void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
8478 * mono_array_setref:
8479 * \param array array to alter
8480 * \param index index into the array
8481 * \param value value to set
8482 * Reference Type version. This sets the \p index's element of the
8483 * \p array with elements of size sizeof(type) to the provided \p value.
8485 * This macro does not attempt to perform type checking or bounds checking.
8487 * Use this to reference types in a \c MonoArray.
8489 void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
8495 * \param array array on which to operate on
8496 * \param element_type C element type (example: \c MonoString*, \c int, \c MonoObject*)
8497 * \param index index into the array
8499 * Use this macro to retrieve the \p index element of an \p array and
8500 * extract the value assuming that the elements of the array match
8501 * the provided type value.
8503 * This method can be used with both arrays holding value types and
8504 * reference types. For reference types, the \p type parameter should
8505 * be a \c MonoObject* or any subclass of it, like \c MonoString*.
8507 * This macro does not attempt to perform type checking or bounds checking.
8509 * \returns The element at the \p index position in the \p array.
8511 Type mono_array_get (MonoArray *array, Type element_type, uintptr_t index)