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));
746 /*An Ephemeron cannot be marked by sgen*/
747 if (!static_fields && klass->image == mono_defaults.corlib && !strcmp ("Ephemeron", klass->name)) {
749 memset (bitmap, 0, size / 8);
754 for (p = klass; p != NULL; p = p->parent) {
755 gpointer iter = NULL;
756 while ((field = mono_class_get_fields (p, &iter))) {
760 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
762 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
765 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
768 /* FIXME: should not happen, flag as type load error */
769 if (field->type->byref)
772 if (static_fields && field->offset == -1)
776 pos = field->offset / sizeof (gpointer);
779 type = mono_type_get_underlying_type (field->type);
780 switch (type->type) {
784 case MONO_TYPE_FNPTR:
786 case MONO_TYPE_STRING:
787 case MONO_TYPE_SZARRAY:
788 case MONO_TYPE_CLASS:
789 case MONO_TYPE_OBJECT:
790 case MONO_TYPE_ARRAY:
791 g_assert ((field->offset % sizeof(gpointer)) == 0);
793 g_assert (pos < size || pos <= max_size);
794 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
795 *max_set = MAX (*max_set, pos);
797 case MONO_TYPE_GENERICINST:
798 if (!mono_type_generic_inst_is_valuetype (type)) {
799 g_assert ((field->offset % sizeof(gpointer)) == 0);
801 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
802 *max_set = MAX (*max_set, pos);
807 case MONO_TYPE_VALUETYPE: {
808 MonoClass *fclass = mono_class_from_mono_type (field->type);
809 if (fclass->has_references) {
810 /* remove the object header */
811 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
825 case MONO_TYPE_BOOLEAN:
829 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
840 * mono_class_compute_bitmap:
842 * Mono internal function to compute a bitmap of reference fields in a class.
845 mono_class_compute_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
847 MONO_REQ_GC_NEUTRAL_MODE;
849 return compute_class_bitmap (klass, bitmap, size, offset, max_set, static_fields);
854 * similar to the above, but sets the bits in the bitmap for any non-ref field
855 * and ignores static fields
858 compute_class_non_ref_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset)
860 MonoClassField *field;
865 max_size = class->instance_size / sizeof (gpointer);
866 if (max_size >= size) {
867 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
870 for (p = class; p != NULL; p = p->parent) {
871 gpointer iter = NULL;
872 while ((field = mono_class_get_fields (p, &iter))) {
875 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
877 /* FIXME: should not happen, flag as type load error */
878 if (field->type->byref)
881 pos = field->offset / sizeof (gpointer);
884 type = mono_type_get_underlying_type (field->type);
885 switch (type->type) {
886 #if SIZEOF_VOID_P == 8
890 case MONO_TYPE_FNPTR:
895 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
896 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
897 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
900 #if SIZEOF_VOID_P == 4
904 case MONO_TYPE_FNPTR:
909 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
910 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
911 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
917 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
918 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
919 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
922 case MONO_TYPE_BOOLEAN:
925 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
927 case MONO_TYPE_STRING:
928 case MONO_TYPE_SZARRAY:
929 case MONO_TYPE_CLASS:
930 case MONO_TYPE_OBJECT:
931 case MONO_TYPE_ARRAY:
933 case MONO_TYPE_GENERICINST:
934 if (!mono_type_generic_inst_is_valuetype (type)) {
939 case MONO_TYPE_VALUETYPE: {
940 MonoClass *fclass = mono_class_from_mono_type (field->type);
941 /* remove the object header */
942 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
946 g_assert_not_reached ();
955 * mono_class_insecure_overlapping:
956 * check if a class with explicit layout has references and non-references
957 * fields overlapping.
959 * Returns: TRUE if it is insecure to load the type.
962 mono_class_insecure_overlapping (MonoClass *klass)
966 gsize default_bitmap [4] = {0};
968 gsize default_nrbitmap [4] = {0};
969 int i, insecure = FALSE;
972 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
973 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
975 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
976 int idx = i % (sizeof (bitmap [0]) * 8);
977 if (bitmap [idx] & nrbitmap [idx]) {
982 if (bitmap != default_bitmap)
984 if (nrbitmap != default_nrbitmap)
987 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
995 ves_icall_string_alloc (int length)
998 MonoString *str = mono_string_new_size_checked (mono_domain_get (), length, &error);
999 mono_error_set_pending_exception (&error);
1004 /* LOCKING: Acquires the loader lock */
1006 mono_class_compute_gc_descriptor (MonoClass *klass)
1008 MONO_REQ_GC_NEUTRAL_MODE;
1012 gsize default_bitmap [4] = {0};
1013 static gboolean gcj_inited = FALSE;
1014 MonoGCDescriptor gc_descr;
1017 mono_loader_lock ();
1019 mono_register_jit_icall (ves_icall_object_new_fast, "ves_icall_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
1020 mono_register_jit_icall (ves_icall_string_alloc, "ves_icall_string_alloc", mono_create_icall_signature ("object int"), FALSE);
1023 mono_loader_unlock ();
1027 mono_class_init (klass);
1029 if (klass->gc_descr_inited)
1032 bitmap = default_bitmap;
1033 if (klass == mono_defaults.string_class) {
1034 gc_descr = mono_gc_make_descr_for_string (bitmap, 2);
1035 } else if (klass->rank) {
1036 mono_class_compute_gc_descriptor (klass->element_class);
1037 if (MONO_TYPE_IS_REFERENCE (&klass->element_class->byval_arg)) {
1039 gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
1040 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1041 class->name_space, class->name);*/
1043 /* remove the object header */
1044 bitmap = compute_class_bitmap (klass->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
1045 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));
1046 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1047 class->name_space, class->name);*/
1048 if (bitmap != default_bitmap)
1052 /*static int count = 0;
1055 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1056 gc_descr = mono_gc_make_descr_for_object (bitmap, max_set + 1, klass->instance_size);
1058 if (class->gc_descr == MONO_GC_DESCRIPTOR_NULL)
1059 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
1061 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
1062 if (bitmap != default_bitmap)
1066 /* Publish the data */
1067 mono_loader_lock ();
1068 klass->gc_descr = gc_descr;
1069 mono_memory_barrier ();
1070 klass->gc_descr_inited = TRUE;
1071 mono_loader_unlock ();
1075 * field_is_special_static:
1076 * @fklass: The MonoClass to look up.
1077 * @field: The MonoClassField describing the field.
1079 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1080 * SPECIAL_STATIC_NONE otherwise.
1083 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1085 MONO_REQ_GC_NEUTRAL_MODE;
1088 MonoCustomAttrInfo *ainfo;
1090 ainfo = mono_custom_attrs_from_field_checked (fklass, field, &error);
1091 mono_error_cleanup (&error); /* FIXME don't swallow the error? */
1094 for (i = 0; i < ainfo->num_attrs; ++i) {
1095 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1096 if (klass->image == mono_defaults.corlib) {
1097 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1098 mono_custom_attrs_free (ainfo);
1099 return SPECIAL_STATIC_THREAD;
1101 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1102 mono_custom_attrs_free (ainfo);
1103 return SPECIAL_STATIC_CONTEXT;
1107 mono_custom_attrs_free (ainfo);
1108 return SPECIAL_STATIC_NONE;
1111 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1112 #define mix(a,b,c) { \
1113 a -= c; a ^= rot(c, 4); c += b; \
1114 b -= a; b ^= rot(a, 6); a += c; \
1115 c -= b; c ^= rot(b, 8); b += a; \
1116 a -= c; a ^= rot(c,16); c += b; \
1117 b -= a; b ^= rot(a,19); a += c; \
1118 c -= b; c ^= rot(b, 4); b += a; \
1120 #define final(a,b,c) { \
1121 c ^= b; c -= rot(b,14); \
1122 a ^= c; a -= rot(c,11); \
1123 b ^= a; b -= rot(a,25); \
1124 c ^= b; c -= rot(b,16); \
1125 a ^= c; a -= rot(c,4); \
1126 b ^= a; b -= rot(a,14); \
1127 c ^= b; c -= rot(b,24); \
1131 * mono_method_get_imt_slot:
1133 * The IMT slot is embedded into AOTed code, so this must return the same value
1134 * for the same method across all executions. This means:
1135 * - pointers shouldn't be used as hash values.
1136 * - mono_metadata_str_hash () should be used for hashing strings.
1139 mono_method_get_imt_slot (MonoMethod *method)
1141 MONO_REQ_GC_NEUTRAL_MODE;
1143 MonoMethodSignature *sig;
1145 guint32 *hashes_start, *hashes;
1149 /* This can be used to stress tests the collision code */
1153 * We do this to simplify generic sharing. It will hurt
1154 * performance in cases where a class implements two different
1155 * instantiations of the same generic interface.
1156 * The code in build_imt_slots () depends on this.
1158 if (method->is_inflated)
1159 method = ((MonoMethodInflated*)method)->declaring;
1161 sig = mono_method_signature (method);
1162 hashes_count = sig->param_count + 4;
1163 hashes_start = (guint32 *)malloc (hashes_count * sizeof (guint32));
1164 hashes = hashes_start;
1166 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1167 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1168 method->klass->name_space, method->klass->name, method->name);
1171 /* Initialize hashes */
1172 hashes [0] = mono_metadata_str_hash (method->klass->name);
1173 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1174 hashes [2] = mono_metadata_str_hash (method->name);
1175 hashes [3] = mono_metadata_type_hash (sig->ret);
1176 for (i = 0; i < sig->param_count; i++) {
1177 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1180 /* Setup internal state */
1181 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1183 /* Handle most of the hashes */
1184 while (hashes_count > 3) {
1193 /* Handle the last 3 hashes (all the case statements fall through) */
1194 switch (hashes_count) {
1195 case 3 : c += hashes [2];
1196 case 2 : b += hashes [1];
1197 case 1 : a += hashes [0];
1199 case 0: /* nothing left to add */
1203 g_free (hashes_start);
1204 /* Report the result */
1205 return c % MONO_IMT_SIZE;
1214 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1215 MONO_REQ_GC_NEUTRAL_MODE;
1217 guint32 imt_slot = mono_method_get_imt_slot (method);
1218 MonoImtBuilderEntry *entry;
1220 if (slot_num >= 0 && imt_slot != slot_num) {
1221 /* we build just a single imt slot and this is not it */
1225 entry = (MonoImtBuilderEntry *)g_malloc0 (sizeof (MonoImtBuilderEntry));
1226 entry->key = method;
1227 entry->value.vtable_slot = vtable_slot;
1228 entry->next = imt_builder [imt_slot];
1229 if (imt_builder [imt_slot] != NULL) {
1230 entry->children = imt_builder [imt_slot]->children + 1;
1231 if (entry->children == 1) {
1232 mono_stats.imt_slots_with_collisions++;
1233 *imt_collisions_bitmap |= (1 << imt_slot);
1236 entry->children = 0;
1237 mono_stats.imt_used_slots++;
1239 imt_builder [imt_slot] = entry;
1242 char *method_name = mono_method_full_name (method, TRUE);
1243 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1244 method, method_name, imt_slot, vtable_slot, entry->children);
1245 g_free (method_name);
1252 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1254 MonoMethod *method = e->key;
1255 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1259 method->klass->name_space,
1260 method->klass->name,
1263 printf (" * %s: NULL\n", message);
1269 compare_imt_builder_entries (const void *p1, const void *p2) {
1270 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1271 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1273 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1277 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1279 MONO_REQ_GC_NEUTRAL_MODE;
1281 int count = end - start;
1282 int chunk_start = out_array->len;
1285 for (i = start; i < end; ++i) {
1286 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1287 item->key = sorted_array [i]->key;
1288 item->value = sorted_array [i]->value;
1289 item->has_target_code = sorted_array [i]->has_target_code;
1290 item->is_equals = TRUE;
1292 item->check_target_idx = out_array->len + 1;
1294 item->check_target_idx = 0;
1295 g_ptr_array_add (out_array, item);
1298 int middle = start + count / 2;
1299 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1301 item->key = sorted_array [middle]->key;
1302 item->is_equals = FALSE;
1303 g_ptr_array_add (out_array, item);
1304 imt_emit_ir (sorted_array, start, middle, out_array);
1305 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1311 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1312 MONO_REQ_GC_NEUTRAL_MODE;
1314 int number_of_entries = entries->children + 1;
1315 MonoImtBuilderEntry **sorted_array = (MonoImtBuilderEntry **)malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1316 GPtrArray *result = g_ptr_array_new ();
1317 MonoImtBuilderEntry *current_entry;
1320 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1321 sorted_array [i] = current_entry;
1323 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1325 /*for (i = 0; i < number_of_entries; i++) {
1326 print_imt_entry (" sorted array:", sorted_array [i], i);
1329 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1331 g_free (sorted_array);
1336 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1338 MONO_REQ_GC_NEUTRAL_MODE;
1340 if (imt_builder_entry != NULL) {
1341 if (imt_builder_entry->children == 0 && !fail_tramp && !always_build_imt_trampolines) {
1342 /* No collision, return the vtable slot contents */
1343 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1345 /* Collision, build the trampoline */
1346 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1349 result = imt_trampoline_builder (vtable, domain,
1350 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1351 for (i = 0; i < imt_ir->len; ++i)
1352 g_free (g_ptr_array_index (imt_ir, i));
1353 g_ptr_array_free (imt_ir, TRUE);
1365 static MonoImtBuilderEntry*
1366 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1369 * LOCKING: requires the loader and domain locks.
1373 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1375 MONO_REQ_GC_NEUTRAL_MODE;
1379 guint32 imt_collisions_bitmap = 0;
1380 MonoImtBuilderEntry **imt_builder = (MonoImtBuilderEntry **)calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1381 int method_count = 0;
1382 gboolean record_method_count_for_max_collisions = FALSE;
1383 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1386 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1388 for (i = 0; i < klass->interface_offsets_count; ++i) {
1389 MonoClass *iface = klass->interfaces_packed [i];
1390 int interface_offset = klass->interface_offsets_packed [i];
1391 int method_slot_in_interface, vt_slot;
1393 if (mono_class_has_variant_generic_params (iface))
1394 has_variant_iface = TRUE;
1396 mono_class_setup_methods (iface);
1397 vt_slot = interface_offset;
1398 int mcount = mono_class_get_method_count (iface);
1399 for (method_slot_in_interface = 0; method_slot_in_interface < mcount; method_slot_in_interface++) {
1402 if (slot_num >= 0 && mono_class_is_ginst (iface)) {
1404 * The imt slot of the method is the same as for its declaring method,
1405 * see the comment in mono_method_get_imt_slot (), so we can
1406 * avoid inflating methods which will be discarded by
1407 * add_imt_builder_entry anyway.
1409 method = mono_class_get_method_by_index (mono_class_get_generic_class (iface)->container_class, method_slot_in_interface);
1410 if (mono_method_get_imt_slot (method) != slot_num) {
1415 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1416 if (method->is_generic) {
1417 has_generic_virtual = TRUE;
1422 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1423 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1428 if (extra_interfaces) {
1429 int interface_offset = klass->vtable_size;
1431 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1432 MonoClass* iface = (MonoClass *)list_item->data;
1433 int method_slot_in_interface;
1434 int mcount = mono_class_get_method_count (iface);
1435 for (method_slot_in_interface = 0; method_slot_in_interface < mcount; method_slot_in_interface++) {
1436 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1438 if (method->is_generic)
1439 has_generic_virtual = TRUE;
1440 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1442 interface_offset += mcount;
1445 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1446 /* overwrite the imt slot only if we're building all the entries or if
1447 * we're building this specific one
1449 if (slot_num < 0 || i == slot_num) {
1450 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1453 if (imt_builder [i]) {
1454 MonoImtBuilderEntry *entry;
1456 /* Link entries with imt_builder [i] */
1457 for (entry = entries; entry->next; entry = entry->next) {
1459 MonoMethod *method = (MonoMethod*)entry->key;
1460 char *method_name = mono_method_full_name (method, TRUE);
1461 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1462 g_free (method_name);
1465 entry->next = imt_builder [i];
1466 entries->children += imt_builder [i]->children + 1;
1468 imt_builder [i] = entries;
1471 if (has_generic_virtual || has_variant_iface) {
1473 * There might be collisions later when the the trampoline is expanded.
1475 imt_collisions_bitmap |= (1 << i);
1478 * The IMT trampoline might be called with an instance of one of the
1479 * generic virtual methods, so has to fallback to the IMT trampoline.
1481 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline (vt, i));
1483 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1486 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1490 if (imt_builder [i] != NULL) {
1491 int methods_in_slot = imt_builder [i]->children + 1;
1492 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1493 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1494 record_method_count_for_max_collisions = TRUE;
1496 method_count += methods_in_slot;
1500 mono_stats.imt_number_of_methods += method_count;
1501 if (record_method_count_for_max_collisions) {
1502 mono_stats.imt_method_count_when_max_collisions = method_count;
1505 for (i = 0; i < MONO_IMT_SIZE; i++) {
1506 MonoImtBuilderEntry* entry = imt_builder [i];
1507 while (entry != NULL) {
1508 MonoImtBuilderEntry* next = entry->next;
1513 g_free (imt_builder);
1514 /* we OR the bitmap since we may build just a single imt slot at a time */
1515 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1519 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1520 MONO_REQ_GC_NEUTRAL_MODE;
1522 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1526 * mono_vtable_build_imt_slot:
1527 * \param vtable virtual object table struct
1528 * \param imt_slot slot in the IMT table
1529 * Fill the given \p imt_slot in the IMT table of \p vtable with
1530 * a trampoline or a trampoline for the case of collisions.
1531 * This is part of the internal mono API.
1532 * LOCKING: Take the domain lock.
1535 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1537 MONO_REQ_GC_NEUTRAL_MODE;
1539 gpointer *imt = (gpointer*)vtable;
1540 imt -= MONO_IMT_SIZE;
1541 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1543 /* no support for extra interfaces: the proxy objects will need
1544 * to build the complete IMT
1545 * Update and heck needs to ahppen inside the proper domain lock, as all
1546 * the changes made to a MonoVTable.
1548 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1549 mono_domain_lock (vtable->domain);
1550 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1551 if (!callbacks.imt_entry_inited (vtable, imt_slot))
1552 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1553 mono_domain_unlock (vtable->domain);
1554 mono_loader_unlock ();
1557 #define THUNK_THRESHOLD 10
1560 * mono_method_alloc_generic_virtual_trampoline:
1561 * \param domain a domain
1562 * \param size size in bytes
1563 * Allocs \p size bytes to be used for the code of a generic virtual
1564 * trampoline. It's either allocated from the domain's code manager or
1565 * reused from a previously invalidated piece.
1566 * LOCKING: The domain lock must be held.
1569 mono_method_alloc_generic_virtual_trampoline (MonoDomain *domain, int size)
1571 MONO_REQ_GC_NEUTRAL_MODE;
1573 static gboolean inited = FALSE;
1574 static int generic_virtual_trampolines_size = 0;
1577 mono_counters_register ("Generic virtual trampoline bytes",
1578 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_trampolines_size);
1581 generic_virtual_trampolines_size += size;
1583 return mono_domain_code_reserve (domain, size);
1586 typedef struct _GenericVirtualCase {
1590 struct _GenericVirtualCase *next;
1591 } GenericVirtualCase;
1594 * get_generic_virtual_entries:
1596 * Return IMT entries for the generic virtual method instances and
1597 * variant interface methods for vtable slot
1600 static MonoImtBuilderEntry*
1601 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1603 MONO_REQ_GC_NEUTRAL_MODE;
1605 GenericVirtualCase *list;
1606 MonoImtBuilderEntry *entries;
1608 mono_domain_lock (domain);
1609 if (!domain->generic_virtual_cases)
1610 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1612 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1615 for (; list; list = list->next) {
1616 MonoImtBuilderEntry *entry;
1618 if (list->count < THUNK_THRESHOLD)
1621 entry = g_new0 (MonoImtBuilderEntry, 1);
1622 entry->key = list->method;
1623 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1624 entry->has_target_code = 1;
1626 entry->children = entries->children + 1;
1627 entry->next = entries;
1631 mono_domain_unlock (domain);
1633 /* FIXME: Leaking memory ? */
1638 * \param domain a domain
1639 * \param vtable_slot pointer to the vtable slot
1640 * \param method the inflated generic virtual method
1641 * \param code the method's code
1643 * Registers a call via unmanaged code to a generic virtual method
1644 * instantiation or variant interface method. If the number of calls reaches a threshold
1645 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1646 * virtual method trampoline.
1649 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1650 gpointer *vtable_slot,
1651 MonoMethod *method, gpointer code)
1653 MONO_REQ_GC_NEUTRAL_MODE;
1655 static gboolean inited = FALSE;
1656 static int num_added = 0;
1657 static int num_freed = 0;
1659 GenericVirtualCase *gvc, *list;
1660 MonoImtBuilderEntry *entries;
1664 mono_domain_lock (domain);
1665 if (!domain->generic_virtual_cases)
1666 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1669 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1670 mono_counters_register ("Freed IMT trampolines", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_freed);
1674 /* Check whether the case was already added */
1675 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1678 if (gvc->method == method)
1683 /* If not found, make a new one */
1685 gvc = (GenericVirtualCase *)mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1686 gvc->method = method;
1689 gvc->next = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1691 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1696 if (++gvc->count == THUNK_THRESHOLD) {
1697 gpointer *old_thunk = (void **)*vtable_slot;
1698 gpointer vtable_trampoline = NULL;
1699 gpointer imt_trampoline = NULL;
1701 if ((gpointer)vtable_slot < (gpointer)vtable) {
1702 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1703 int imt_slot = MONO_IMT_SIZE + displacement;
1705 /* Force the rebuild of the trampoline at the next call */
1706 imt_trampoline = callbacks.get_imt_trampoline (vtable, imt_slot);
1707 *vtable_slot = imt_trampoline;
1709 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline (vtable, (gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1711 entries = get_generic_virtual_entries (domain, vtable_slot);
1713 sorted = imt_sort_slot_entries (entries);
1715 *vtable_slot = imt_trampoline_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1719 MonoImtBuilderEntry *next = entries->next;
1724 for (i = 0; i < sorted->len; ++i)
1725 g_free (g_ptr_array_index (sorted, i));
1726 g_ptr_array_free (sorted, TRUE);
1728 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1733 mono_domain_unlock (domain);
1736 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error);
1739 * mono_class_vtable:
1740 * \param domain the application domain
1741 * \param class the class to initialize
1742 * VTables are domain specific because we create domain specific code, and
1743 * they contain the domain specific static class data.
1744 * On failure, NULL is returned, and \c class->exception_type is set.
1747 mono_class_vtable (MonoDomain *domain, MonoClass *klass)
1750 MonoVTable* vtable = mono_class_vtable_full (domain, klass, &error);
1751 mono_error_cleanup (&error);
1756 * mono_class_vtable_full:
1757 * \param domain the application domain
1758 * \param class the class to initialize
1759 * \param error set on failure.
1760 * VTables are domain specific because we create domain specific code, and
1761 * they contain the domain specific static class data.
1764 mono_class_vtable_full (MonoDomain *domain, MonoClass *klass, MonoError *error)
1766 MONO_REQ_GC_UNSAFE_MODE;
1768 MonoClassRuntimeInfo *runtime_info;
1774 if (mono_class_has_failure (klass)) {
1775 mono_error_set_for_class_failure (error, klass);
1779 /* this check can be inlined in jitted code, too */
1780 runtime_info = klass->runtime_info;
1781 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1782 return runtime_info->domain_vtables [domain->domain_id];
1783 return mono_class_create_runtime_vtable (domain, klass, error);
1787 * mono_class_try_get_vtable:
1788 * \param domain the application domain
1789 * \param class the class to initialize
1790 * This function tries to get the associated vtable from \p class if
1791 * it was already created.
1794 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *klass)
1796 MONO_REQ_GC_NEUTRAL_MODE;
1798 MonoClassRuntimeInfo *runtime_info;
1802 runtime_info = klass->runtime_info;
1803 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1804 return runtime_info->domain_vtables [domain->domain_id];
1809 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1811 MONO_REQ_GC_NEUTRAL_MODE;
1813 size_t alloc_offset;
1816 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1817 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1818 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1820 if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1821 g_assert ((imt_table_bytes & 7) == 4);
1828 return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1832 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error)
1834 MONO_REQ_GC_UNSAFE_MODE;
1837 MonoClassRuntimeInfo *runtime_info, *old_info;
1838 MonoClassField *field;
1840 int i, vtable_slots;
1841 size_t imt_table_bytes;
1843 guint32 vtable_size, class_size;
1845 gpointer *interface_offsets;
1849 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1850 mono_domain_lock (domain);
1851 runtime_info = klass->runtime_info;
1852 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1853 mono_domain_unlock (domain);
1854 mono_loader_unlock ();
1855 return runtime_info->domain_vtables [domain->domain_id];
1857 if (!klass->inited || mono_class_has_failure (klass)) {
1858 if (!mono_class_init (klass) || mono_class_has_failure (klass)) {
1859 mono_domain_unlock (domain);
1860 mono_loader_unlock ();
1861 mono_error_set_for_class_failure (error, klass);
1866 /* Array types require that their element type be valid*/
1867 if (klass->byval_arg.type == MONO_TYPE_ARRAY || klass->byval_arg.type == MONO_TYPE_SZARRAY) {
1868 MonoClass *element_class = klass->element_class;
1869 if (!element_class->inited)
1870 mono_class_init (element_class);
1872 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1873 if (!mono_class_has_failure (element_class) && !element_class->vtable_size)
1874 mono_class_setup_vtable (element_class);
1876 if (mono_class_has_failure (element_class)) {
1877 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1878 if (!mono_class_has_failure (klass))
1879 mono_class_set_type_load_failure (klass, "");
1880 mono_domain_unlock (domain);
1881 mono_loader_unlock ();
1882 mono_error_set_for_class_failure (error, klass);
1888 * For some classes, mono_class_init () already computed klass->vtable_size, and
1889 * that is all that is needed because of the vtable trampolines.
1891 if (!klass->vtable_size)
1892 mono_class_setup_vtable (klass);
1894 if (mono_class_is_ginst (klass) && !klass->vtable)
1895 mono_class_check_vtable_constraints (klass, NULL);
1897 /* Initialize klass->has_finalize */
1898 mono_class_has_finalizer (klass);
1900 if (mono_class_has_failure (klass)) {
1901 mono_domain_unlock (domain);
1902 mono_loader_unlock ();
1903 mono_error_set_for_class_failure (error, klass);
1907 vtable_slots = klass->vtable_size;
1908 /* we add an additional vtable slot to store the pointer to static field data only when needed */
1909 class_size = mono_class_data_size (klass);
1913 if (klass->interface_offsets_count) {
1914 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1915 mono_stats.imt_number_of_tables++;
1916 mono_stats.imt_tables_size += imt_table_bytes;
1918 imt_table_bytes = 0;
1921 vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
1923 mono_stats.used_class_count++;
1924 mono_stats.class_vtable_size += vtable_size;
1926 interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
1927 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1928 g_assert (!((gsize)vt & 7));
1931 vt->rank = klass->rank;
1932 vt->domain = domain;
1934 mono_class_compute_gc_descriptor (klass);
1936 * We can't use typed allocation in the non-root domains, since the
1937 * collector needs the GC descriptor stored in the vtable even after
1938 * the mempool containing the vtable is destroyed when the domain is
1939 * unloaded. An alternative might be to allocate vtables in the GC
1940 * heap, but this does not seem to work (it leads to crashes inside
1941 * libgc). If that approach is tried, two gc descriptors need to be
1942 * allocated for each class: one for the root domain, and one for all
1943 * other domains. The second descriptor should contain a bit for the
1944 * vtable field in MonoObject, since we can no longer assume the
1945 * vtable is reachable by other roots after the appdomain is unloaded.
1947 #ifdef HAVE_BOEHM_GC
1948 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1949 vt->gc_descr = MONO_GC_DESCRIPTOR_NULL;
1952 vt->gc_descr = klass->gc_descr;
1954 gc_bits = mono_gc_get_vtable_bits (klass);
1955 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
1957 vt->gc_bits = gc_bits;
1960 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
1961 if (klass->has_static_refs) {
1962 MonoGCDescriptor statics_gc_descr;
1964 gsize default_bitmap [4] = {0};
1967 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1968 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], klass->name_space, klass->name, class_size);*/
1969 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1970 vt->vtable [klass->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr, MONO_ROOT_SOURCE_STATIC, "managed static variables");
1971 if (bitmap != default_bitmap)
1974 vt->vtable [klass->vtable_size] = mono_domain_alloc0 (domain, class_size);
1976 vt->has_static_fields = TRUE;
1977 mono_stats.class_static_data_size += class_size;
1981 while ((field = mono_class_get_fields (klass, &iter))) {
1982 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1984 if (mono_field_is_deleted (field))
1986 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1987 gint32 special_static = klass->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (klass, field);
1988 if (special_static != SPECIAL_STATIC_NONE) {
1989 guint32 size, offset;
1991 gsize default_bitmap [4] = {0};
1996 if (mono_type_is_reference (field->type)) {
1997 default_bitmap [0] = 1;
1999 bitmap = default_bitmap;
2000 } else if (mono_type_is_struct (field->type)) {
2001 fclass = mono_class_from_mono_type (field->type);
2002 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
2003 numbits = max_set + 1;
2005 default_bitmap [0] = 0;
2007 bitmap = default_bitmap;
2009 size = mono_type_size (field->type, &align);
2010 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
2011 if (!domain->special_static_fields)
2012 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2013 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2014 if (bitmap != default_bitmap)
2017 * This marks the field as special static to speed up the
2018 * checks in mono_field_static_get/set_value ().
2024 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2025 MonoClass *fklass = mono_class_from_mono_type (field->type);
2026 const char *data = mono_field_get_data (field);
2028 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2029 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2030 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2033 if (fklass->valuetype) {
2034 memcpy (t, data, mono_class_value_size (fklass, NULL));
2036 /* it's a pointer type: add check */
2037 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2044 vt->max_interface_id = klass->max_interface_id;
2045 vt->interface_bitmap = klass->interface_bitmap;
2047 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2048 // class->name, klass->interface_offsets_count);
2050 /* Initialize vtable */
2051 if (callbacks.get_vtable_trampoline) {
2052 // This also covers the AOT case
2053 for (i = 0; i < klass->vtable_size; ++i) {
2054 vt->vtable [i] = callbacks.get_vtable_trampoline (vt, i);
2057 mono_class_setup_vtable (klass);
2059 for (i = 0; i < klass->vtable_size; ++i) {
2062 cm = klass->vtable [i];
2064 vt->vtable [i] = callbacks.create_jit_trampoline (domain, cm, error);
2065 if (!is_ok (error)) {
2066 mono_domain_unlock (domain);
2067 mono_loader_unlock ();
2074 if (imt_table_bytes) {
2075 /* Now that the vtable is full, we can actually fill up the IMT */
2076 for (i = 0; i < MONO_IMT_SIZE; ++i)
2077 interface_offsets [i] = callbacks.get_imt_trampoline (vt, i);
2081 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2082 * re-acquire them and check if another thread has created the vtable in the meantime.
2084 /* Special case System.MonoType to avoid infinite recursion */
2085 if (klass != mono_defaults.runtimetype_class) {
2086 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2087 if (!is_ok (error)) {
2088 mono_domain_unlock (domain);
2089 mono_loader_unlock ();
2093 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2094 /* This is unregistered in
2095 unregister_vtable_reflection_type() in
2097 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2100 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (klass));
2102 /* class_vtable_array keeps an array of created vtables
2104 g_ptr_array_add (domain->class_vtable_array, vt);
2105 /* klass->runtime_info is protected by the loader lock, both when
2106 * it it enlarged and when it is stored info.
2110 * Store the vtable in klass->runtime_info.
2111 * klass->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2113 mono_memory_barrier ();
2115 old_info = klass->runtime_info;
2116 if (old_info && old_info->max_domain >= domain->domain_id) {
2117 /* someone already created a large enough runtime info */
2118 old_info->domain_vtables [domain->domain_id] = vt;
2120 int new_size = domain->domain_id;
2122 new_size = MAX (new_size, old_info->max_domain);
2124 /* make the new size a power of two */
2126 while (new_size > i)
2129 /* this is a bounded memory retention issue: may want to
2130 * handle it differently when we'll have a rcu-like system.
2132 runtime_info = (MonoClassRuntimeInfo *)mono_image_alloc0 (klass->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2133 runtime_info->max_domain = new_size - 1;
2134 /* copy the stuff from the older info */
2136 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2138 runtime_info->domain_vtables [domain->domain_id] = vt;
2140 mono_memory_barrier ();
2141 klass->runtime_info = runtime_info;
2144 if (klass == mono_defaults.runtimetype_class) {
2145 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2146 if (!is_ok (error)) {
2147 mono_domain_unlock (domain);
2148 mono_loader_unlock ();
2152 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2153 /* This is unregistered in
2154 unregister_vtable_reflection_type() in
2156 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2159 mono_domain_unlock (domain);
2160 mono_loader_unlock ();
2162 /* make sure the parent is initialized */
2163 /*FIXME shouldn't this fail the current type?*/
2165 mono_class_vtable_full (domain, klass->parent, error);
2170 #ifndef DISABLE_REMOTING
2172 * mono_class_proxy_vtable:
2173 * \param domain the application domain
2174 * \param remove_class the remote class
2175 * \param error set on error
2176 * Creates a vtable for transparent proxies. It is basically
2177 * a copy of the real vtable of the class wrapped in \p remote_class,
2178 * but all function pointers invoke the remoting functions, and
2179 * \c vtable->klass points to the transparent proxy class, and not to \p class.
2181 * On failure returns NULL and sets \p error
2184 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type, MonoError *error)
2186 MONO_REQ_GC_UNSAFE_MODE;
2188 MonoVTable *vt, *pvt;
2189 int i, j, vtsize, extra_interface_vtsize = 0;
2190 guint32 max_interface_id;
2192 GSList *extra_interfaces = NULL;
2193 MonoClass *klass = remote_class->proxy_class;
2194 gpointer *interface_offsets;
2195 uint8_t *bitmap = NULL;
2197 size_t imt_table_bytes;
2199 #ifdef COMPRESSED_INTERFACE_BITMAP
2205 vt = mono_class_vtable (domain, klass);
2206 g_assert (vt); /*FIXME property handle failure*/
2207 max_interface_id = vt->max_interface_id;
2209 /* Calculate vtable space for extra interfaces */
2210 for (j = 0; j < remote_class->interface_count; j++) {
2211 MonoClass* iclass = remote_class->interfaces[j];
2215 /*FIXME test for interfaces with variant generic arguments*/
2216 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, iclass->interface_id))
2217 continue; /* interface implemented by the class */
2218 if (g_slist_find (extra_interfaces, iclass))
2221 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2223 method_count = mono_class_num_methods (iclass);
2225 ifaces = mono_class_get_implemented_interfaces (iclass, error);
2229 for (i = 0; i < ifaces->len; ++i) {
2230 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2231 /*FIXME test for interfaces with variant generic arguments*/
2232 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, ic->interface_id))
2233 continue; /* interface implemented by the class */
2234 if (g_slist_find (extra_interfaces, ic))
2236 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2237 method_count += mono_class_num_methods (ic);
2239 g_ptr_array_free (ifaces, TRUE);
2243 extra_interface_vtsize += method_count * sizeof (gpointer);
2244 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2247 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2248 mono_stats.imt_number_of_tables++;
2249 mono_stats.imt_tables_size += imt_table_bytes;
2251 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer);
2253 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2255 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2256 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2257 g_assert (!((gsize)pvt & 7));
2259 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer));
2261 pvt->klass = mono_defaults.transparent_proxy_class;
2262 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2263 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2265 /* initialize vtable */
2266 mono_class_setup_vtable (klass);
2267 for (i = 0; i < klass->vtable_size; ++i) {
2270 if ((cm = klass->vtable [i])) {
2271 pvt->vtable [i] = create_remoting_trampoline (domain, cm, target_type, error);
2275 pvt->vtable [i] = NULL;
2278 if (mono_class_is_abstract (klass)) {
2279 /* create trampolines for abstract methods */
2280 for (k = klass; k; k = k->parent) {
2282 gpointer iter = NULL;
2283 while ((m = mono_class_get_methods (k, &iter)))
2284 if (!pvt->vtable [m->slot]) {
2285 pvt->vtable [m->slot] = create_remoting_trampoline (domain, m, target_type, error);
2292 pvt->max_interface_id = max_interface_id;
2293 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2294 #ifdef COMPRESSED_INTERFACE_BITMAP
2295 bitmap = (uint8_t *)g_malloc0 (bsize);
2297 bitmap = (uint8_t *)mono_domain_alloc0 (domain, bsize);
2300 for (i = 0; i < klass->interface_offsets_count; ++i) {
2301 int interface_id = klass->interfaces_packed [i]->interface_id;
2302 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2305 if (extra_interfaces) {
2306 int slot = klass->vtable_size;
2312 /* Create trampolines for the methods of the interfaces */
2313 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2314 interf = (MonoClass *)list_item->data;
2316 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2320 while ((cm = mono_class_get_methods (interf, &iter))) {
2321 pvt->vtable [slot + j++] = create_remoting_trampoline (domain, cm, target_type, error);
2326 slot += mono_class_num_methods (interf);
2330 /* Now that the vtable is full, we can actually fill up the IMT */
2331 build_imt (klass, pvt, domain, interface_offsets, extra_interfaces);
2332 if (extra_interfaces) {
2333 g_slist_free (extra_interfaces);
2336 #ifdef COMPRESSED_INTERFACE_BITMAP
2337 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2338 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2339 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2342 pvt->interface_bitmap = bitmap;
2346 if (extra_interfaces)
2347 g_slist_free (extra_interfaces);
2348 #ifdef COMPRESSED_INTERFACE_BITMAP
2354 #endif /* DISABLE_REMOTING */
2357 * mono_class_field_is_special_static:
2358 * \returns whether \p field is a thread/context static field.
2361 mono_class_field_is_special_static (MonoClassField *field)
2363 MONO_REQ_GC_NEUTRAL_MODE
2365 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2367 if (mono_field_is_deleted (field))
2369 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2370 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2377 * mono_class_field_get_special_static_type:
2378 * \param field The \c MonoClassField describing the field.
2379 * \returns \c SPECIAL_STATIC_THREAD if the field is thread static, \c SPECIAL_STATIC_CONTEXT if it is context static,
2380 * \c SPECIAL_STATIC_NONE otherwise.
2383 mono_class_field_get_special_static_type (MonoClassField *field)
2385 MONO_REQ_GC_NEUTRAL_MODE
2387 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2388 return SPECIAL_STATIC_NONE;
2389 if (mono_field_is_deleted (field))
2390 return SPECIAL_STATIC_NONE;
2391 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2392 return field_is_special_static (field->parent, field);
2393 return SPECIAL_STATIC_NONE;
2397 * mono_class_has_special_static_fields:
2398 * \returns whether \p klass has any thread/context static fields.
2401 mono_class_has_special_static_fields (MonoClass *klass)
2403 MONO_REQ_GC_NEUTRAL_MODE
2405 MonoClassField *field;
2409 while ((field = mono_class_get_fields (klass, &iter))) {
2410 g_assert (field->parent == klass);
2411 if (mono_class_field_is_special_static (field))
2418 #ifndef DISABLE_REMOTING
2420 * create_remote_class_key:
2421 * Creates an array of pointers that can be used as a hash key for a remote class.
2422 * The first element of the array is the number of pointers.
2425 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2427 MONO_REQ_GC_NEUTRAL_MODE;
2432 if (remote_class == NULL) {
2433 if (mono_class_is_interface (extra_class)) {
2434 key = (void **)g_malloc (sizeof(gpointer) * 3);
2435 key [0] = GINT_TO_POINTER (2);
2436 key [1] = mono_defaults.marshalbyrefobject_class;
2437 key [2] = extra_class;
2439 key = (void **)g_malloc (sizeof(gpointer) * 2);
2440 key [0] = GINT_TO_POINTER (1);
2441 key [1] = extra_class;
2444 if (extra_class != NULL && mono_class_is_interface (extra_class)) {
2445 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2446 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2447 key [1] = remote_class->proxy_class;
2449 // Keep the list of interfaces sorted
2450 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2451 if (extra_class && remote_class->interfaces [i] > extra_class) {
2452 key [j++] = extra_class;
2455 key [j] = remote_class->interfaces [i];
2458 key [j] = extra_class;
2460 // Replace the old class. The interface list is the same
2461 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2462 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2463 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2464 for (i = 0; i < remote_class->interface_count; i++)
2465 key [2 + i] = remote_class->interfaces [i];
2473 * copy_remote_class_key:
2475 * Make a copy of KEY in the domain and return the copy.
2478 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2480 MONO_REQ_GC_NEUTRAL_MODE
2482 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2483 gpointer *mp_key = (gpointer *)mono_domain_alloc (domain, key_size);
2485 memcpy (mp_key, key, key_size);
2491 * mono_remote_class:
2492 * \param domain the application domain
2493 * \param class_name name of the remote class
2494 * \param error set on error
2495 * Creates and initializes a \c MonoRemoteClass object for a remote type.
2496 * On failure returns NULL and sets \p error
2499 mono_remote_class (MonoDomain *domain, MonoStringHandle class_name, MonoClass *proxy_class, MonoError *error)
2501 MONO_REQ_GC_UNSAFE_MODE;
2503 MonoRemoteClass *rc;
2504 gpointer* key, *mp_key;
2509 key = create_remote_class_key (NULL, proxy_class);
2511 mono_domain_lock (domain);
2512 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2516 mono_domain_unlock (domain);
2520 name = mono_string_to_utf8_mp (domain->mp, MONO_HANDLE_RAW (class_name), error);
2521 if (!is_ok (error)) {
2523 mono_domain_unlock (domain);
2527 mp_key = copy_remote_class_key (domain, key);
2531 if (mono_class_is_interface (proxy_class)) {
2532 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2533 rc->interface_count = 1;
2534 rc->interfaces [0] = proxy_class;
2535 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2537 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2538 rc->interface_count = 0;
2539 rc->proxy_class = proxy_class;
2542 rc->default_vtable = NULL;
2543 rc->xdomain_vtable = NULL;
2544 rc->proxy_class_name = name;
2545 #ifndef DISABLE_PERFCOUNTERS
2546 mono_perfcounters->loader_bytes += mono_string_length (MONO_HANDLE_RAW (class_name)) + 1;
2549 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2551 mono_domain_unlock (domain);
2556 * clone_remote_class:
2557 * Creates a copy of the remote_class, adding the provided class or interface
2559 static MonoRemoteClass*
2560 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2562 MONO_REQ_GC_NEUTRAL_MODE;
2564 MonoRemoteClass *rc;
2565 gpointer* key, *mp_key;
2567 key = create_remote_class_key (remote_class, extra_class);
2568 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2574 mp_key = copy_remote_class_key (domain, key);
2578 if (mono_class_is_interface (extra_class)) {
2580 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2581 rc->proxy_class = remote_class->proxy_class;
2582 rc->interface_count = remote_class->interface_count + 1;
2584 // Keep the list of interfaces sorted, since the hash key of
2585 // the remote class depends on this
2586 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2587 if (remote_class->interfaces [i] > extra_class && i == j)
2588 rc->interfaces [j++] = extra_class;
2589 rc->interfaces [j] = remote_class->interfaces [i];
2592 rc->interfaces [j] = extra_class;
2594 // Replace the old class. The interface array is the same
2595 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2596 rc->proxy_class = extra_class;
2597 rc->interface_count = remote_class->interface_count;
2598 if (rc->interface_count > 0)
2599 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2602 rc->default_vtable = NULL;
2603 rc->xdomain_vtable = NULL;
2604 rc->proxy_class_name = remote_class->proxy_class_name;
2606 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2612 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxyHandle rp, MonoError *error)
2614 MONO_REQ_GC_UNSAFE_MODE;
2618 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2619 mono_domain_lock (domain);
2620 gint32 target_domain_id = MONO_HANDLE_GETVAL (rp, target_domain_id);
2621 if (target_domain_id != -1) {
2622 if (remote_class->xdomain_vtable == NULL)
2623 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN, error);
2624 mono_domain_unlock (domain);
2625 mono_loader_unlock ();
2626 return_val_if_nok (error, NULL);
2627 return remote_class->xdomain_vtable;
2629 if (remote_class->default_vtable == NULL) {
2630 MonoReflectionTypeHandle reftype = MONO_HANDLE_NEW (MonoReflectionType, NULL);
2631 MONO_HANDLE_GET (reftype, rp, class_to_proxy);
2633 MonoType *type = MONO_HANDLE_GETVAL (reftype, type);
2634 MonoClass *klass = mono_class_from_mono_type (type);
2636 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)))
2637 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP, error);
2640 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN, error);
2641 /* N.B. both branches of the if modify error */
2642 if (!is_ok (error)) {
2643 mono_domain_unlock (domain);
2644 mono_loader_unlock ();
2649 mono_domain_unlock (domain);
2650 mono_loader_unlock ();
2651 return remote_class->default_vtable;
2655 * mono_upgrade_remote_class:
2656 * \param domain the application domain
2657 * \param tproxy the proxy whose remote class has to be upgraded.
2658 * \param klass class to which the remote class can be casted.
2659 * \param error set on error
2660 * Updates the vtable of the remote class by adding the necessary method slots
2661 * and interface offsets so it can be safely casted to klass. klass can be a
2662 * class or an interface. On success returns TRUE, on failure returns FALSE and sets \p error.
2665 mono_upgrade_remote_class (MonoDomain *domain, MonoObjectHandle proxy_object, MonoClass *klass, MonoError *error)
2667 MONO_REQ_GC_UNSAFE_MODE;
2671 MonoTransparentProxyHandle tproxy = MONO_HANDLE_CAST (MonoTransparentProxy, proxy_object);
2672 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (tproxy, remote_class);
2674 gboolean redo_vtable;
2675 if (mono_class_is_interface (klass)) {
2678 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2679 if (remote_class->interfaces [i] == klass)
2680 redo_vtable = FALSE;
2683 redo_vtable = (remote_class->proxy_class != klass);
2686 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2687 mono_domain_lock (domain);
2689 MonoRemoteClass *fresh_remote_class = clone_remote_class (domain, remote_class, klass);
2690 MONO_HANDLE_SETVAL (tproxy, remote_class, MonoRemoteClass*, fresh_remote_class);
2691 MonoRealProxyHandle real_proxy = MONO_HANDLE_NEW (MonoRealProxy, NULL);
2692 MONO_HANDLE_GET (real_proxy, tproxy, rp);
2693 MONO_HANDLE_SETVAL (proxy_object, vtable, MonoVTable*, mono_remote_class_vtable (domain, fresh_remote_class, real_proxy, error));
2699 mono_domain_unlock (domain);
2700 mono_loader_unlock ();
2701 return is_ok (error);
2703 #endif /* DISABLE_REMOTING */
2707 * mono_object_get_virtual_method:
2708 * \param obj object to operate on.
2709 * \param method method
2710 * Retrieves the \c MonoMethod that would be called on \p obj if \p obj is passed as
2711 * the instance of a callvirt of \p method.
2714 mono_object_get_virtual_method (MonoObject *obj_raw, MonoMethod *method)
2716 MONO_REQ_GC_UNSAFE_MODE;
2717 HANDLE_FUNCTION_ENTER ();
2719 MONO_HANDLE_DCL (MonoObject, obj);
2720 MonoMethod *result = mono_object_handle_get_virtual_method (obj, method, &error);
2721 mono_error_assert_ok (&error);
2722 HANDLE_FUNCTION_RETURN_VAL (result);
2726 * mono_object_handle_get_virtual_method:
2727 * \param obj object to operate on.
2728 * \param method method
2729 * Retrieves the \c MonoMethod that would be called on \p obj if \p obj is passed as
2730 * the instance of a callvirt of \p method.
2733 mono_object_handle_get_virtual_method (MonoObjectHandle obj, MonoMethod *method, MonoError *error)
2737 gboolean is_proxy = FALSE;
2738 MonoClass *klass = mono_handle_class (obj);
2739 if (mono_class_is_transparent_proxy (klass)) {
2740 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), remote_class);
2741 klass = remote_class->proxy_class;
2744 return class_get_virtual_method (klass, method, is_proxy, error);
2748 class_get_virtual_method (MonoClass *klass, MonoMethod *method, gboolean is_proxy, MonoError *error)
2753 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2756 mono_class_setup_vtable (klass);
2757 MonoMethod **vtable = klass->vtable;
2759 if (method->slot == -1) {
2760 /* method->slot might not be set for instances of generic methods */
2761 if (method->is_inflated) {
2762 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2763 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2766 g_assert_not_reached ();
2770 MonoMethod *res = NULL;
2771 /* check method->slot is a valid index: perform isinstance? */
2772 if (method->slot != -1) {
2773 if (mono_class_is_interface (method->klass)) {
2775 gboolean variance_used = FALSE;
2776 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2777 g_assert (iface_offset > 0);
2778 res = vtable [iface_offset + method->slot];
2781 res = vtable [method->slot];
2785 #ifndef DISABLE_REMOTING
2787 /* It may be an interface, abstract class method or generic method */
2788 if (!res || mono_method_signature (res)->generic_param_count)
2791 /* generic methods demand invoke_with_check */
2792 if (mono_method_signature (res)->generic_param_count)
2793 res = mono_marshal_get_remoting_invoke_with_check (res);
2796 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2797 res = mono_cominterop_get_invoke (res);
2800 res = mono_marshal_get_remoting_invoke (res);
2805 if (method->is_inflated) {
2806 /* Have to inflate the result */
2807 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, error);
2815 do_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2817 MONO_REQ_GC_UNSAFE_MODE;
2819 MonoObject *result = NULL;
2821 g_assert (callbacks.runtime_invoke);
2825 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2826 mono_profiler_method_start_invoke (method);
2828 result = callbacks.runtime_invoke (method, obj, params, exc, error);
2830 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2831 mono_profiler_method_end_invoke (method);
2833 if (!mono_error_ok (error))
2840 * mono_runtime_invoke:
2841 * \param method method to invoke
2842 * \param obj object instance
2843 * \param params arguments to the method
2844 * \param exc exception information.
2845 * Invokes the method represented by \p method on the object \p obj.
2846 * \p obj is the \c this pointer, it should be NULL for static
2847 * methods, a \c MonoObject* for object instances and a pointer to
2848 * the value type for value types.
2850 * The params array contains the arguments to the method with the
2851 * same convention: \c MonoObject* pointers for object instances and
2852 * pointers to the value type otherwise.
2854 * From unmanaged code you'll usually use the
2855 * \c mono_runtime_invoke variant.
2857 * Note that this function doesn't handle virtual methods for
2858 * you, it will exec the exact method you pass: we still need to
2859 * expose a function to lookup the derived class implementation
2860 * of a virtual method (there are examples of this in the code,
2863 * You can pass NULL as the \p exc argument if you don't want to
2864 * catch exceptions, otherwise, \c *exc will be set to the exception
2865 * thrown, if any. if an exception is thrown, you can't use the
2866 * \c MonoObject* result from the function.
2868 * If the method returns a value type, it is boxed in an object
2872 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2877 res = mono_runtime_try_invoke (method, obj, params, exc, &error);
2878 if (*exc == NULL && !mono_error_ok(&error)) {
2879 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
2881 mono_error_cleanup (&error);
2883 res = mono_runtime_invoke_checked (method, obj, params, &error);
2884 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
2890 * mono_runtime_try_invoke:
2891 * \param method method to invoke
2892 * \param obj object instance
2893 * \param params arguments to the method
2894 * \param exc exception information.
2895 * \param error set on error
2896 * Invokes the method represented by \p method on the object \p obj.
2898 * \p obj is the \c this pointer, it should be NULL for static
2899 * methods, a \c MonoObject* for object instances and a pointer to
2900 * the value type for value types.
2902 * The params array contains the arguments to the method with the
2903 * same convention: \c MonoObject* pointers for object instances and
2904 * pointers to the value type otherwise.
2906 * From unmanaged code you'll usually use the
2907 * mono_runtime_invoke() variant.
2909 * Note that this function doesn't handle virtual methods for
2910 * you, it will exec the exact method you pass: we still need to
2911 * expose a function to lookup the derived class implementation
2912 * of a virtual method (there are examples of this in the code,
2915 * For this function, you must not pass NULL as the \p exc argument if
2916 * you don't want to catch exceptions, use
2917 * mono_runtime_invoke_checked(). If an exception is thrown, you
2918 * can't use the \c MonoObject* result from the function.
2920 * If this method cannot be invoked, \p error will be set and \p exc and
2921 * the return value must not be used.
2923 * If the method returns a value type, it is boxed in an object
2927 mono_runtime_try_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError* error)
2929 MONO_REQ_GC_UNSAFE_MODE;
2931 g_assert (exc != NULL);
2933 if (mono_runtime_get_no_exec ())
2934 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2936 return do_runtime_invoke (method, obj, params, exc, error);
2940 * mono_runtime_invoke_checked:
2941 * \param method method to invoke
2942 * \param obj object instance
2943 * \param params arguments to the method
2944 * \param error set on error
2945 * Invokes the method represented by \p method on the object \p obj.
2947 * \p obj is the \c this pointer, it should be NULL for static
2948 * methods, a \c MonoObject* for object instances and a pointer to
2949 * the value type for value types.
2951 * The \p params array contains the arguments to the method with the
2952 * same convention: \c MonoObject* pointers for object instances and
2953 * pointers to the value type otherwise.
2955 * From unmanaged code you'll usually use the
2956 * mono_runtime_invoke() variant.
2958 * Note that this function doesn't handle virtual methods for
2959 * you, it will exec the exact method you pass: we still need to
2960 * expose a function to lookup the derived class implementation
2961 * of a virtual method (there are examples of this in the code,
2964 * If an exception is thrown, you can't use the \c MonoObject* result
2965 * from the function.
2967 * If this method cannot be invoked, \p error will be set. If the
2968 * method throws an exception (and we're in coop mode) the exception
2969 * will be set in \p error.
2971 * If the method returns a value type, it is boxed in an object
2975 mono_runtime_invoke_checked (MonoMethod *method, void *obj, void **params, MonoError* error)
2977 MONO_REQ_GC_UNSAFE_MODE;
2979 if (mono_runtime_get_no_exec ())
2980 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2982 return do_runtime_invoke (method, obj, params, NULL, error);
2986 * mono_method_get_unmanaged_thunk:
2987 * \param method method to generate a thunk for.
2989 * Returns an \c unmanaged->managed thunk that can be used to call
2990 * a managed method directly from C.
2992 * The thunk's C signature closely matches the managed signature:
2994 * C#: <code>public bool Equals (object obj);</code>
2996 * C: <code>typedef MonoBoolean (*Equals)(MonoObject*, MonoObject*, MonoException**);</code>
2998 * The 1st (<code>this</code>) parameter must not be used with static methods:
3000 * C#: <code>public static bool ReferenceEquals (object a, object b);</code>
3002 * C: <code>typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*, MonoException**);</code>
3004 * The last argument must be a non-null \c MonoException* pointer.
3005 * It has "out" semantics. After invoking the thunk, \c *ex will be NULL if no
3006 * exception has been thrown in managed code. Otherwise it will point
3007 * to the \c MonoException* caught by the thunk. In this case, the result of
3008 * the thunk is undefined:
3011 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
3013 * MonoException *ex = NULL;
3015 * Equals func = mono_method_get_unmanaged_thunk (method);
3017 * MonoBoolean res = func (thisObj, objToCompare, &ex);
3021 * // handle exception
3026 * The calling convention of the thunk matches the platform's default
3027 * convention. This means that under Windows, C declarations must
3028 * contain the \c __stdcall attribute:
3030 * C: <code>typedef MonoBoolean (__stdcall *Equals)(MonoObject*, MonoObject*, MonoException**);</code>
3034 * Value type arguments and return values are treated as they were objects:
3036 * C#: <code>public static Rectangle Intersect (Rectangle a, Rectangle b);</code>
3037 * C: <code>typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);</code>
3039 * Arguments must be properly boxed upon trunk's invocation, while return
3040 * values must be unboxed.
3043 mono_method_get_unmanaged_thunk (MonoMethod *method)
3045 MONO_REQ_GC_NEUTRAL_MODE;
3046 MONO_REQ_API_ENTRYPOINT;
3051 g_assert (!mono_threads_is_coop_enabled ());
3053 MONO_ENTER_GC_UNSAFE;
3054 method = mono_marshal_get_thunk_invoke_wrapper (method);
3055 res = mono_compile_method_checked (method, &error);
3056 mono_error_cleanup (&error);
3057 MONO_EXIT_GC_UNSAFE;
3063 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
3065 MONO_REQ_GC_UNSAFE_MODE;
3069 /* object fields cannot be byref, so we don't need a
3071 gpointer *p = (gpointer*)dest;
3078 case MONO_TYPE_BOOLEAN:
3080 case MONO_TYPE_U1: {
3081 guint8 *p = (guint8*)dest;
3082 *p = value ? *(guint8*)value : 0;
3087 case MONO_TYPE_CHAR: {
3088 guint16 *p = (guint16*)dest;
3089 *p = value ? *(guint16*)value : 0;
3092 #if SIZEOF_VOID_P == 4
3097 case MONO_TYPE_U4: {
3098 gint32 *p = (gint32*)dest;
3099 *p = value ? *(gint32*)value : 0;
3102 #if SIZEOF_VOID_P == 8
3107 case MONO_TYPE_U8: {
3108 gint64 *p = (gint64*)dest;
3109 *p = value ? *(gint64*)value : 0;
3112 case MONO_TYPE_R4: {
3113 float *p = (float*)dest;
3114 *p = value ? *(float*)value : 0;
3117 case MONO_TYPE_R8: {
3118 double *p = (double*)dest;
3119 *p = value ? *(double*)value : 0;
3122 case MONO_TYPE_STRING:
3123 case MONO_TYPE_SZARRAY:
3124 case MONO_TYPE_CLASS:
3125 case MONO_TYPE_OBJECT:
3126 case MONO_TYPE_ARRAY:
3127 mono_gc_wbarrier_generic_store (dest, deref_pointer ? *(MonoObject **)value : (MonoObject *)value);
3129 case MONO_TYPE_FNPTR:
3130 case MONO_TYPE_PTR: {
3131 gpointer *p = (gpointer*)dest;
3132 *p = deref_pointer? *(gpointer*)value: value;
3135 case MONO_TYPE_VALUETYPE:
3136 /* note that 't' and 'type->type' can be different */
3137 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3138 t = mono_class_enum_basetype (type->data.klass)->type;
3141 MonoClass *klass = mono_class_from_mono_type (type);
3142 int size = mono_class_value_size (klass, NULL);
3144 mono_gc_bzero_atomic (dest, size);
3146 mono_gc_wbarrier_value_copy (dest, value, 1, klass);
3149 case MONO_TYPE_GENERICINST:
3150 t = type->data.generic_class->container_class->byval_arg.type;
3153 g_error ("got type %x", type->type);
3158 * mono_field_set_value:
3159 * \param obj Instance object
3160 * \param field \c MonoClassField describing the field to set
3161 * \param value The value to be set
3163 * Sets the value of the field described by \p field in the object instance \p obj
3164 * to the value passed in \p value. This method should only be used for instance
3165 * fields. For static fields, use \c mono_field_static_set_value.
3167 * The value must be in the native format of the field type.
3170 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3172 MONO_REQ_GC_UNSAFE_MODE;
3176 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3178 dest = (char*)obj + field->offset;
3179 mono_copy_value (field->type, dest, value, FALSE);
3183 * mono_field_static_set_value:
3184 * \param field \c MonoClassField describing the field to set
3185 * \param value The value to be set
3186 * Sets the value of the static field described by \p field
3187 * to the value passed in \p value.
3188 * The value must be in the native format of the field type.
3191 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3193 MONO_REQ_GC_UNSAFE_MODE;
3197 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3198 /* you cant set a constant! */
3199 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3201 if (field->offset == -1) {
3202 /* Special static */
3205 mono_domain_lock (vt->domain);
3206 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3207 mono_domain_unlock (vt->domain);
3208 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3210 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3212 mono_copy_value (field->type, dest, value, FALSE);
3216 * mono_vtable_get_static_field_data:
3218 * Internal use function: return a pointer to the memory holding the static fields
3219 * for a class or NULL if there are no static fields.
3220 * This is exported only for use by the debugger.
3223 mono_vtable_get_static_field_data (MonoVTable *vt)
3225 MONO_REQ_GC_NEUTRAL_MODE
3227 if (!vt->has_static_fields)
3229 return vt->vtable [vt->klass->vtable_size];
3233 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3235 MONO_REQ_GC_UNSAFE_MODE;
3239 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3240 if (field->offset == -1) {
3241 /* Special static */
3244 mono_domain_lock (vt->domain);
3245 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3246 mono_domain_unlock (vt->domain);
3247 src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3249 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3252 src = (guint8*)obj + field->offset;
3259 * mono_field_get_value:
3260 * \param obj Object instance
3261 * \param field \c MonoClassField describing the field to fetch information from
3262 * \param value pointer to the location where the value will be stored
3263 * Use this routine to get the value of the field \p field in the object
3266 * The pointer provided by value must be of the field type, for reference
3267 * types this is a \c MonoObject*, for value types its the actual pointer to
3275 * mono_field_get_value (obj, int_field, &i);
3279 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3281 MONO_REQ_GC_UNSAFE_MODE;
3287 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3289 src = (char*)obj + field->offset;
3290 mono_copy_value (field->type, value, src, TRUE);
3294 * mono_field_get_value_object:
3295 * \param domain domain where the object will be created (if boxing)
3296 * \param field \c MonoClassField describing the field to fetch information from
3297 * \param obj The object instance for the field.
3298 * \returns a new \c MonoObject with the value from the given field. If the
3299 * field represents a value type, the value is boxed.
3302 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3305 MonoObject* result = mono_field_get_value_object_checked (domain, field, obj, &error);
3306 mono_error_assert_ok (&error);
3311 * mono_field_get_value_object_checked:
3312 * \param domain domain where the object will be created (if boxing)
3313 * \param field \c MonoClassField describing the field to fetch information from
3314 * \param obj The object instance for the field.
3315 * \param error Set on error.
3316 * \returns a new \c MonoObject with the value from the given field. If the
3317 * field represents a value type, the value is boxed. On error returns NULL and sets \p error.
3320 mono_field_get_value_object_checked (MonoDomain *domain, MonoClassField *field, MonoObject *obj, MonoError *error)
3322 MONO_REQ_GC_UNSAFE_MODE;
3328 MonoVTable *vtable = NULL;
3330 gboolean is_static = FALSE;
3331 gboolean is_ref = FALSE;
3332 gboolean is_literal = FALSE;
3333 gboolean is_ptr = FALSE;
3334 MonoType *type = mono_field_get_type_checked (field, error);
3336 return_val_if_nok (error, NULL);
3338 switch (type->type) {
3339 case MONO_TYPE_STRING:
3340 case MONO_TYPE_OBJECT:
3341 case MONO_TYPE_CLASS:
3342 case MONO_TYPE_ARRAY:
3343 case MONO_TYPE_SZARRAY:
3348 case MONO_TYPE_BOOLEAN:
3351 case MONO_TYPE_CHAR:
3360 case MONO_TYPE_VALUETYPE:
3361 is_ref = type->byref;
3363 case MONO_TYPE_GENERICINST:
3364 is_ref = !mono_type_generic_inst_is_valuetype (type);
3370 g_error ("type 0x%x not handled in "
3371 "mono_field_get_value_object", type->type);
3375 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3378 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3382 vtable = mono_class_vtable_full (domain, field->parent, error);
3383 return_val_if_nok (error, NULL);
3385 if (!vtable->initialized) {
3386 mono_runtime_class_init_full (vtable, error);
3387 return_val_if_nok (error, NULL);
3396 get_default_field_value (domain, field, &o, error);
3397 return_val_if_nok (error, NULL);
3398 } else if (is_static) {
3399 mono_field_static_get_value_checked (vtable, field, &o, error);
3400 return_val_if_nok (error, NULL);
3402 mono_field_get_value (obj, field, &o);
3408 static MonoMethod *m;
3414 MonoClass *ptr_klass = mono_class_get_pointer_class ();
3415 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3421 get_default_field_value (domain, field, v, error);
3422 return_val_if_nok (error, NULL);
3423 } else if (is_static) {
3424 mono_field_static_get_value_checked (vtable, field, v, error);
3425 return_val_if_nok (error, NULL);
3427 mono_field_get_value (obj, field, v);
3430 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3431 args [0] = ptr ? *ptr : NULL;
3432 args [1] = mono_type_get_object_checked (mono_domain_get (), type, error);
3433 return_val_if_nok (error, NULL);
3435 o = mono_runtime_invoke_checked (m, NULL, args, error);
3436 return_val_if_nok (error, NULL);
3441 /* boxed value type */
3442 klass = mono_class_from_mono_type (type);
3444 if (mono_class_is_nullable (klass))
3445 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass, error);
3447 o = mono_object_new_checked (domain, klass, error);
3448 return_val_if_nok (error, NULL);
3449 v = ((gchar *) o) + sizeof (MonoObject);
3452 get_default_field_value (domain, field, v, error);
3453 return_val_if_nok (error, NULL);
3454 } else if (is_static) {
3455 mono_field_static_get_value_checked (vtable, field, v, error);
3456 return_val_if_nok (error, NULL);
3458 mono_field_get_value (obj, field, v);
3465 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value, MonoError *error)
3467 MONO_REQ_GC_UNSAFE_MODE;
3471 const char *p = blob;
3472 mono_metadata_decode_blob_size (p, &p);
3475 case MONO_TYPE_BOOLEAN:
3478 *(guint8 *) value = *p;
3480 case MONO_TYPE_CHAR:
3483 *(guint16*) value = read16 (p);
3487 *(guint32*) value = read32 (p);
3491 *(guint64*) value = read64 (p);
3494 readr4 (p, (float*) value);
3497 readr8 (p, (double*) value);
3499 case MONO_TYPE_STRING:
3500 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob, error);
3502 case MONO_TYPE_CLASS:
3503 *(gpointer*) value = NULL;
3507 g_warning ("type 0x%02x should not be in constant table", type);
3513 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error)
3515 MONO_REQ_GC_NEUTRAL_MODE;
3517 MonoTypeEnum def_type;
3522 data = mono_class_get_field_default_value (field, &def_type);
3523 mono_get_constant_value_from_blob (domain, def_type, data, value, error);
3527 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3529 MONO_REQ_GC_UNSAFE_MODE;
3535 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3537 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3538 get_default_field_value (vt->domain, field, value, error);
3542 if (field->offset == -1) {
3543 /* Special static */
3544 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3545 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3547 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3549 mono_copy_value (field->type, value, src, TRUE);
3553 * mono_field_static_get_value:
3554 * \param vt vtable to the object
3555 * \param field \c MonoClassField describing the field to fetch information from
3556 * \param value where the value is returned
3557 * Use this routine to get the value of the static field \p field value.
3559 * The pointer provided by value must be of the field type, for reference
3560 * types this is a \c MonoObject*, for value types its the actual pointer to
3568 * mono_field_static_get_value (vt, int_field, &i);
3572 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3574 MONO_REQ_GC_NEUTRAL_MODE;
3577 mono_field_static_get_value_checked (vt, field, value, &error);
3578 mono_error_cleanup (&error);
3582 * mono_field_static_get_value_checked:
3583 * \param vt vtable to the object
3584 * \param field \c MonoClassField describing the field to fetch information from
3585 * \param value where the value is returned
3586 * \param error set on error
3587 * Use this routine to get the value of the static field \p field value.
3589 * The pointer provided by value must be of the field type, for reference
3590 * types this is a \c MonoObject*, for value types its the actual pointer to
3595 * mono_field_static_get_value_checked (vt, int_field, &i, error);
3596 * if (!is_ok (error)) { ... }
3598 * On failure sets \p error.
3601 mono_field_static_get_value_checked (MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3603 MONO_REQ_GC_NEUTRAL_MODE;
3605 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value, error);
3609 * mono_property_set_value:
3610 * \param prop MonoProperty to set
3611 * \param obj instance object on which to act
3612 * \param params parameters to pass to the propery
3613 * \param exc optional exception
3614 * Invokes the property's set method with the given arguments on the
3615 * object instance obj (or NULL for static properties).
3617 * You can pass NULL as the exc argument if you don't want to
3618 * catch exceptions, otherwise, \c *exc will be set to the exception
3619 * thrown, if any. if an exception is thrown, you can't use the
3620 * \c MonoObject* result from the function.
3623 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3625 MONO_REQ_GC_UNSAFE_MODE;
3628 do_runtime_invoke (prop->set, obj, params, exc, &error);
3629 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3630 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3632 mono_error_cleanup (&error);
3637 * mono_property_set_value_checked:
3638 * \param prop \c MonoProperty to set
3639 * \param obj instance object on which to act
3640 * \param params parameters to pass to the propery
3641 * \param error set on error
3642 * Invokes the property's set method with the given arguments on the
3643 * object instance \p obj (or NULL for static properties).
3644 * \returns TRUE on success. On failure returns FALSE and sets \p error.
3645 * If an exception is thrown, it will be caught and returned via \p error.
3648 mono_property_set_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3650 MONO_REQ_GC_UNSAFE_MODE;
3655 do_runtime_invoke (prop->set, obj, params, &exc, error);
3656 if (exc != NULL && is_ok (error))
3657 mono_error_set_exception_instance (error, (MonoException*)exc);
3658 return is_ok (error);
3662 * mono_property_get_value:
3663 * \param prop \c MonoProperty to fetch
3664 * \param obj instance object on which to act
3665 * \param params parameters to pass to the propery
3666 * \param exc optional exception
3667 * Invokes the property's \c get method with the given arguments on the
3668 * object instance \p obj (or NULL for static properties).
3670 * You can pass NULL as the \p exc argument if you don't want to
3671 * catch exceptions, otherwise, \c *exc will be set to the exception
3672 * thrown, if any. if an exception is thrown, you can't use the
3673 * \c MonoObject* result from the function.
3675 * \returns the value from invoking the \c get method on the property.
3678 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3680 MONO_REQ_GC_UNSAFE_MODE;
3683 MonoObject *val = do_runtime_invoke (prop->get, obj, params, exc, &error);
3684 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3685 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3687 mono_error_cleanup (&error); /* FIXME don't raise here */
3694 * mono_property_get_value_checked:
3695 * \param prop \c MonoProperty to fetch
3696 * \param obj instance object on which to act
3697 * \param params parameters to pass to the propery
3698 * \param error set on error
3699 * Invokes the property's \c get method with the given arguments on the
3700 * object instance obj (or NULL for static properties).
3702 * If an exception is thrown, you can't use the
3703 * \c MonoObject* result from the function. The exception will be propagated via \p error.
3705 * \returns the value from invoking the get method on the property. On
3706 * failure returns NULL and sets \p error.
3709 mono_property_get_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3711 MONO_REQ_GC_UNSAFE_MODE;
3714 MonoObject *val = do_runtime_invoke (prop->get, obj, params, &exc, error);
3715 if (exc != NULL && !is_ok (error))
3716 mono_error_set_exception_instance (error, (MonoException*) exc);
3724 * mono_nullable_init:
3725 * @buf: The nullable structure to initialize.
3726 * @value: the value to initialize from
3727 * @klass: the type for the object
3729 * Initialize the nullable structure pointed to by @buf from @value which
3730 * should be a boxed value type. The size of @buf should be able to hold
3731 * as much data as the @klass->instance_size (which is the number of bytes
3732 * that will be copies).
3734 * Since Nullables have variable structure, we can not define a C
3735 * structure for them.
3738 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3740 MONO_REQ_GC_UNSAFE_MODE;
3742 MonoClass *param_class = klass->cast_class;
3744 mono_class_setup_fields (klass);
3745 g_assert (klass->fields_inited);
3747 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3748 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3750 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3752 if (param_class->has_references)
3753 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3755 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3757 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3762 * mono_nullable_box:
3763 * \param buf The buffer representing the data to be boxed
3764 * \param klass the type to box it as.
3765 * \param error set on error
3767 * Creates a boxed vtype or NULL from the \c Nullable structure pointed to by
3768 * \p buf. On failure returns NULL and sets \p error.
3771 mono_nullable_box (guint8 *buf, MonoClass *klass, MonoError *error)
3773 MONO_REQ_GC_UNSAFE_MODE;
3776 MonoClass *param_class = klass->cast_class;
3778 mono_class_setup_fields (klass);
3779 g_assert (klass->fields_inited);
3781 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3782 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3784 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3785 MonoObject *o = mono_object_new_checked (mono_domain_get (), param_class, error);
3786 return_val_if_nok (error, NULL);
3787 if (param_class->has_references)
3788 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3790 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3798 * mono_get_delegate_invoke:
3799 * \param klass The delegate class
3800 * \returns the \c MonoMethod for the \c Invoke method in the delegate class or NULL if \p klass is a broken delegate type
3803 mono_get_delegate_invoke (MonoClass *klass)
3805 MONO_REQ_GC_NEUTRAL_MODE;
3809 /* This is called at runtime, so avoid the slower search in metadata */
3810 mono_class_setup_methods (klass);
3811 if (mono_class_has_failure (klass))
3813 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3818 * mono_get_delegate_begin_invoke:
3819 * \param klass The delegate class
3820 * \returns the \c MonoMethod for the \c BeginInvoke method in the delegate class or NULL if \p klass is a broken delegate type
3823 mono_get_delegate_begin_invoke (MonoClass *klass)
3825 MONO_REQ_GC_NEUTRAL_MODE;
3829 /* This is called at runtime, so avoid the slower search in metadata */
3830 mono_class_setup_methods (klass);
3831 if (mono_class_has_failure (klass))
3833 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3838 * mono_get_delegate_end_invoke:
3839 * \param klass The delegate class
3840 * \returns the \c MonoMethod for the \c EndInvoke method in the delegate class or NULL if \p klass is a broken delegate type
3843 mono_get_delegate_end_invoke (MonoClass *klass)
3845 MONO_REQ_GC_NEUTRAL_MODE;
3849 /* This is called at runtime, so avoid the slower search in metadata */
3850 mono_class_setup_methods (klass);
3851 if (mono_class_has_failure (klass))
3853 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3858 * mono_runtime_delegate_invoke:
3859 * \param delegate pointer to a delegate object.
3860 * \param params parameters for the delegate.
3861 * \param exc Pointer to the exception result.
3863 * Invokes the delegate method \p delegate with the parameters provided.
3865 * You can pass NULL as the \p exc argument if you don't want to
3866 * catch exceptions, otherwise, \c *exc will be set to the exception
3867 * thrown, if any. if an exception is thrown, you can't use the
3868 * \c MonoObject* result from the function.
3871 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3873 MONO_REQ_GC_UNSAFE_MODE;
3877 MonoObject *result = mono_runtime_delegate_try_invoke (delegate, params, exc, &error);
3879 mono_error_cleanup (&error);
3882 if (!is_ok (&error))
3883 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
3887 MonoObject *result = mono_runtime_delegate_invoke_checked (delegate, params, &error);
3888 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
3894 * mono_runtime_delegate_try_invoke:
3895 * \param delegate pointer to a delegate object.
3896 * \param params parameters for the delegate.
3897 * \param exc Pointer to the exception result.
3898 * \param error set on error
3899 * Invokes the delegate method \p delegate with the parameters provided.
3901 * You can pass NULL as the \p exc argument if you don't want to
3902 * catch exceptions, otherwise, \c *exc will be set to the exception
3903 * thrown, if any. On failure to execute, \p error will be set.
3904 * if an exception is thrown, you can't use the
3905 * \c MonoObject* result from the function.
3908 mono_runtime_delegate_try_invoke (MonoObject *delegate, void **params, MonoObject **exc, MonoError *error)
3910 MONO_REQ_GC_UNSAFE_MODE;
3914 MonoClass *klass = delegate->vtable->klass;
3917 im = mono_get_delegate_invoke (klass);
3919 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3922 o = mono_runtime_try_invoke (im, delegate, params, exc, error);
3924 o = mono_runtime_invoke_checked (im, delegate, params, error);
3931 * mono_runtime_delegate_invoke_checked:
3932 * \param delegate pointer to a delegate object.
3933 * \param params parameters for the delegate.
3934 * \param error set on error
3935 * Invokes the delegate method \p delegate with the parameters provided.
3936 * On failure \p error will be set and you can't use the \c MonoObject*
3937 * result from the function.
3940 mono_runtime_delegate_invoke_checked (MonoObject *delegate, void **params, MonoError *error)
3943 return mono_runtime_delegate_try_invoke (delegate, params, NULL, error);
3946 static char **main_args = NULL;
3947 static int num_main_args = 0;
3950 * mono_runtime_get_main_args:
3951 * \returns A \c MonoArray with the arguments passed to the main program
3954 mono_runtime_get_main_args (void)
3956 MONO_REQ_GC_UNSAFE_MODE;
3958 MonoArray *result = mono_runtime_get_main_args_checked (&error);
3959 mono_error_assert_ok (&error);
3964 * mono_runtime_get_main_args_checked:
3965 * \param error set on error
3966 * \returns a \c MonoArray with the arguments passed to the main
3967 * program. On failure returns NULL and sets \p error.
3970 mono_runtime_get_main_args_checked (MonoError *error)
3974 MonoDomain *domain = mono_domain_get ();
3978 res = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, num_main_args, error);
3979 return_val_if_nok (error, NULL);
3981 for (i = 0; i < num_main_args; ++i)
3982 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3988 free_main_args (void)
3990 MONO_REQ_GC_NEUTRAL_MODE;
3994 for (i = 0; i < num_main_args; ++i)
3995 g_free (main_args [i]);
4002 * mono_runtime_set_main_args:
4003 * \param argc number of arguments from the command line
4004 * \param argv array of strings from the command line
4005 * Set the command line arguments from an embedding application that doesn't otherwise call
4006 * \c mono_runtime_run_main.
4009 mono_runtime_set_main_args (int argc, char* argv[])
4011 MONO_REQ_GC_NEUTRAL_MODE;
4016 main_args = g_new0 (char*, argc);
4017 num_main_args = argc;
4019 for (i = 0; i < argc; ++i) {
4022 utf8_arg = mono_utf8_from_external (argv[i]);
4023 if (utf8_arg == NULL) {
4024 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
4025 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4029 main_args [i] = utf8_arg;
4036 * Prepare an array of arguments in order to execute a standard Main()
4037 * method (argc/argv contains the executable name). This method also
4038 * sets the command line argument value needed by System.Environment.
4042 prepare_run_main (MonoMethod *method, int argc, char *argv[])
4044 MONO_REQ_GC_UNSAFE_MODE;
4048 MonoArray *args = NULL;
4049 MonoDomain *domain = mono_domain_get ();
4050 gchar *utf8_fullpath;
4051 MonoMethodSignature *sig;
4053 g_assert (method != NULL);
4055 mono_thread_set_main (mono_thread_current ());
4057 main_args = g_new0 (char*, argc);
4058 num_main_args = argc;
4060 if (!g_path_is_absolute (argv [0])) {
4061 gchar *basename = g_path_get_basename (argv [0]);
4062 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
4066 utf8_fullpath = mono_utf8_from_external (fullpath);
4067 if(utf8_fullpath == NULL) {
4068 /* Printing the arg text will cause glib to
4069 * whinge about "Invalid UTF-8", but at least
4070 * its relevant, and shows the problem text
4073 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
4074 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4081 utf8_fullpath = mono_utf8_from_external (argv[0]);
4082 if(utf8_fullpath == NULL) {
4083 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
4084 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4089 main_args [0] = utf8_fullpath;
4091 for (i = 1; i < argc; ++i) {
4094 utf8_arg=mono_utf8_from_external (argv[i]);
4095 if(utf8_arg==NULL) {
4096 /* Ditto the comment about Invalid UTF-8 here */
4097 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
4098 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4102 main_args [i] = utf8_arg;
4107 sig = mono_method_signature (method);
4109 g_print ("Unable to load Main method.\n");
4113 if (sig->param_count) {
4114 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, argc, &error);
4115 mono_error_assert_ok (&error);
4116 for (i = 0; i < argc; ++i) {
4117 /* The encodings should all work, given that
4118 * we've checked all these args for the
4121 gchar *str = mono_utf8_from_external (argv [i]);
4122 MonoString *arg = mono_string_new (domain, str);
4123 mono_array_setref (args, i, arg);
4127 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, 0, &error);
4128 mono_error_assert_ok (&error);
4131 mono_assembly_set_main (method->klass->image->assembly);
4137 * mono_runtime_run_main:
4138 * \param method the method to start the application with (usually <code>Main</code>)
4139 * \param argc number of arguments from the command line
4140 * \param argv array of strings from the command line
4141 * \param exc excetption results
4142 * Execute a standard \c Main method (\p argc / \p argv contains the
4143 * executable name). This method also sets the command line argument value
4144 * needed by \c System.Environment.
4147 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
4150 MONO_REQ_GC_UNSAFE_MODE;
4153 MonoArray *args = prepare_run_main (method, argc, argv);
4156 res = mono_runtime_try_exec_main (method, args, exc);
4158 res = mono_runtime_exec_main_checked (method, args, &error);
4159 mono_error_raise_exception (&error); /* OK to throw, external only without a better alternative */
4165 * mono_runtime_run_main_checked:
4166 * \param method the method to start the application with (usually \c Main)
4167 * \param argc number of arguments from the command line
4168 * \param argv array of strings from the command line
4169 * \param error set on error
4171 * Execute a standard \c Main method (\p argc / \p argv contains the
4172 * executable name). This method also sets the command line argument value
4173 * needed by \c System.Environment. On failure sets \p error.
4176 mono_runtime_run_main_checked (MonoMethod *method, int argc, char* argv[],
4180 MonoArray *args = prepare_run_main (method, argc, argv);
4181 return mono_runtime_exec_main_checked (method, args, error);
4185 * mono_runtime_try_run_main:
4186 * \param method the method to start the application with (usually \c Main)
4187 * \param argc number of arguments from the command line
4188 * \param argv array of strings from the command line
4189 * \param exc set if \c Main throws an exception
4190 * \param error set if \c Main can't be executed
4191 * Execute a standard \c Main method (\p argc / \p argv contains the executable
4192 * name). This method also sets the command line argument value needed
4193 * by \c System.Environment. On failure sets \p error if Main can't be
4194 * executed or \p exc if it threw an exception.
4197 mono_runtime_try_run_main (MonoMethod *method, int argc, char* argv[],
4201 MonoArray *args = prepare_run_main (method, argc, argv);
4202 return mono_runtime_try_exec_main (method, args, exc);
4207 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4209 static MonoMethod *serialize_method;
4215 if (!serialize_method) {
4216 MonoClass *klass = mono_class_get_remoting_services_class ();
4217 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
4220 if (!serialize_method) {
4225 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
4230 array = mono_runtime_try_invoke (serialize_method, NULL, params, exc, &error);
4231 if (*exc == NULL && !mono_error_ok (&error))
4232 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert serialize_object to MonoError */
4234 mono_error_cleanup (&error);
4243 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4245 MONO_REQ_GC_UNSAFE_MODE;
4247 static MonoMethod *deserialize_method;
4253 if (!deserialize_method) {
4254 MonoClass *klass = mono_class_get_remoting_services_class ();
4255 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
4257 if (!deserialize_method) {
4265 result = mono_runtime_try_invoke (deserialize_method, NULL, params, exc, &error);
4266 if (*exc == NULL && !mono_error_ok (&error))
4267 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert deserialize_object to MonoError */
4269 mono_error_cleanup (&error);
4277 #ifndef DISABLE_REMOTING
4279 make_transparent_proxy (MonoObject *obj, MonoError *error)
4281 MONO_REQ_GC_UNSAFE_MODE;
4283 static MonoMethod *get_proxy_method;
4285 MonoDomain *domain = mono_domain_get ();
4286 MonoRealProxy *real_proxy;
4287 MonoReflectionType *reflection_type;
4288 MonoTransparentProxy *transparent_proxy;
4292 if (!get_proxy_method)
4293 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
4295 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
4297 real_proxy = (MonoRealProxy*) mono_object_new_checked (domain, mono_defaults.real_proxy_class, error);
4298 return_val_if_nok (error, NULL);
4299 reflection_type = mono_type_get_object_checked (domain, &obj->vtable->klass->byval_arg, error);
4300 return_val_if_nok (error, NULL);
4302 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
4303 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
4305 MonoObject *exc = NULL;
4307 transparent_proxy = (MonoTransparentProxy*) mono_runtime_try_invoke (get_proxy_method, real_proxy, NULL, &exc, error);
4308 if (exc != NULL && is_ok (error))
4309 mono_error_set_exception_instance (error, (MonoException*)exc);
4311 return (MonoObject*) transparent_proxy;
4313 #endif /* DISABLE_REMOTING */
4316 * mono_object_xdomain_representation
4317 * \param obj an object
4318 * \param target_domain a domain
4319 * \param error set on error.
4320 * Creates a representation of obj in the domain \p target_domain. This
4321 * is either a copy of \p obj arrived through via serialization and
4322 * deserialization or a proxy, depending on whether the object is
4323 * serializable or marshal by ref. \p obj must not be in \p target_domain.
4324 * If the object cannot be represented in \p target_domain, NULL is
4325 * returned and \p error is set appropriately.
4328 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoError *error)
4330 MONO_REQ_GC_UNSAFE_MODE;
4333 MonoObject *deserialized = NULL;
4335 #ifndef DISABLE_REMOTING
4336 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
4337 deserialized = make_transparent_proxy (obj, error);
4342 gboolean failure = FALSE;
4343 MonoDomain *domain = mono_domain_get ();
4344 MonoObject *serialized;
4345 MonoObject *exc = NULL;
4347 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
4348 serialized = serialize_object (obj, &failure, &exc);
4349 mono_domain_set_internal_with_options (target_domain, FALSE);
4351 deserialized = deserialize_object (serialized, &failure, &exc);
4352 if (domain != target_domain)
4353 mono_domain_set_internal_with_options (domain, FALSE);
4355 mono_error_set_exception_instance (error, (MonoException*)exc);
4358 return deserialized;
4361 /* Used in call_unhandled_exception_delegate */
4363 create_unhandled_exception_eventargs (MonoObject *exc, MonoError *error)
4365 MONO_REQ_GC_UNSAFE_MODE;
4370 MonoMethod *method = NULL;
4371 MonoBoolean is_terminating = TRUE;
4374 klass = mono_class_get_unhandled_exception_event_args_class ();
4375 mono_class_init (klass);
4377 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4378 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
4382 args [1] = &is_terminating;
4384 obj = mono_object_new_checked (mono_domain_get (), klass, error);
4385 return_val_if_nok (error, NULL);
4387 mono_runtime_invoke_checked (method, obj, args, error);
4388 return_val_if_nok (error, NULL);
4393 /* Used in mono_unhandled_exception */
4395 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4396 MONO_REQ_GC_UNSAFE_MODE;
4399 MonoObject *e = NULL;
4401 MonoDomain *current_domain = mono_domain_get ();
4403 if (domain != current_domain)
4404 mono_domain_set_internal_with_options (domain, FALSE);
4406 g_assert (domain == mono_object_domain (domain->domain));
4408 if (mono_object_domain (exc) != domain) {
4410 exc = mono_object_xdomain_representation (exc, domain, &error);
4412 if (!is_ok (&error)) {
4413 MonoError inner_error;
4414 MonoException *serialization_exc = mono_error_convert_to_exception (&error);
4415 exc = mono_object_xdomain_representation ((MonoObject*)serialization_exc, domain, &inner_error);
4416 mono_error_assert_ok (&inner_error);
4418 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4419 "System.Runtime.Serialization", "SerializationException",
4420 "Could not serialize unhandled exception.");
4424 g_assert (mono_object_domain (exc) == domain);
4426 pa [0] = domain->domain;
4427 pa [1] = create_unhandled_exception_eventargs (exc, &error);
4428 mono_error_assert_ok (&error);
4429 mono_runtime_delegate_try_invoke (delegate, pa, &e, &error);
4430 if (!is_ok (&error)) {
4432 e = (MonoObject*)mono_error_convert_to_exception (&error);
4434 mono_error_cleanup (&error);
4437 if (domain != current_domain)
4438 mono_domain_set_internal_with_options (current_domain, FALSE);
4441 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4442 if (!mono_error_ok (&error)) {
4443 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4444 mono_error_cleanup (&error);
4446 g_warning ("exception inside UnhandledException handler: %s\n", msg);
4452 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4455 * mono_runtime_unhandled_exception_policy_set:
4456 * \param policy the new policy
4457 * This is a VM internal routine.
4458 * Sets the runtime policy for handling unhandled exceptions.
4461 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4462 runtime_unhandled_exception_policy = policy;
4466 * mono_runtime_unhandled_exception_policy_get:
4468 * This is a VM internal routine.
4470 * Gets the runtime policy for handling unhandled exceptions.
4472 MonoRuntimeUnhandledExceptionPolicy
4473 mono_runtime_unhandled_exception_policy_get (void) {
4474 return runtime_unhandled_exception_policy;
4478 * mono_unhandled_exception:
4479 * \param exc exception thrown
4480 * This is a VM internal routine.
4482 * We call this function when we detect an unhandled exception
4483 * in the default domain.
4485 * It invokes the \c UnhandledException event in \c AppDomain or prints
4486 * a warning to the console
4489 mono_unhandled_exception (MonoObject *exc_raw)
4492 HANDLE_FUNCTION_ENTER ();
4493 MONO_HANDLE_DCL (MonoObject, exc);
4494 error_init (&error);
4495 mono_unhandled_exception_checked (exc, &error);
4496 mono_error_assert_ok (&error);
4497 HANDLE_FUNCTION_RETURN ();
4501 * mono_unhandled_exception:
4502 * @exc: exception thrown
4504 * This is a VM internal routine.
4506 * We call this function when we detect an unhandled exception
4507 * in the default domain.
4509 * It invokes the * UnhandledException event in AppDomain or prints
4510 * a warning to the console
4513 mono_unhandled_exception_checked (MonoObjectHandle exc, MonoError *error)
4515 MONO_REQ_GC_UNSAFE_MODE;
4518 MonoClassField *field;
4519 MonoDomain *current_domain, *root_domain;
4520 MonoObjectHandle current_appdomain_delegate = MONO_HANDLE_NEW (MonoObject, NULL);
4522 MonoClass *klass = mono_handle_class (exc);
4523 if (mono_class_has_parent (klass, mono_defaults.threadabortexception_class))
4526 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4529 current_domain = mono_domain_get ();
4530 root_domain = mono_get_root_domain ();
4532 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 */
4533 return_if_nok (error);
4534 if (current_domain != root_domain) {
4535 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 */
4536 return_if_nok (error);
4539 if (MONO_HANDLE_IS_NULL (current_appdomain_delegate) && MONO_HANDLE_IS_NULL (root_appdomain_delegate)) {
4540 mono_print_unhandled_exception (MONO_HANDLE_RAW (exc)); /* FIXME use handles for mono_print_unhandled_exception */
4542 /* unhandled exception callbacks must not be aborted */
4543 mono_threads_begin_abort_protected_block ();
4544 if (!MONO_HANDLE_IS_NULL (root_appdomain_delegate))
4545 call_unhandled_exception_delegate (root_domain, MONO_HANDLE_RAW (root_appdomain_delegate), MONO_HANDLE_RAW (exc)); /* FIXME use handles in call_unhandled_exception_delegate */
4546 if (!MONO_HANDLE_IS_NULL (current_appdomain_delegate))
4547 call_unhandled_exception_delegate (current_domain, MONO_HANDLE_RAW (current_appdomain_delegate), MONO_HANDLE_RAW (exc));
4548 mono_threads_end_abort_protected_block ();
4551 /* set exitcode only if we will abort the process */
4552 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4553 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4555 mono_environment_exitcode_set (1);
4560 * mono_runtime_exec_managed_code:
4561 * \param domain Application domain
4562 * \param main_func function to invoke from the execution thread
4563 * \param main_args parameter to the main_func
4564 * Launch a new thread to execute a function
4566 * \p main_func is called back from the thread with main_args as the
4567 * parameter. The callback function is expected to start \c Main
4568 * eventually. This function then waits for all managed threads to
4570 * It is not necessary anymore to execute managed code in a subthread,
4571 * so this function should not be used anymore by default: just
4572 * execute the code and then call mono_thread_manage().
4575 mono_runtime_exec_managed_code (MonoDomain *domain,
4576 MonoMainThreadFunc main_func,
4580 mono_thread_create_checked (domain, main_func, main_args, &error);
4581 mono_error_assert_ok (&error);
4583 mono_thread_manage ();
4587 prepare_thread_to_exec_main (MonoDomain *domain, MonoMethod *method)
4589 MonoInternalThread* thread = mono_thread_internal_current ();
4590 MonoCustomAttrInfo* cinfo;
4591 gboolean has_stathread_attribute;
4593 if (!domain->entry_assembly) {
4595 MonoAssembly *assembly;
4597 assembly = method->klass->image->assembly;
4598 domain->entry_assembly = assembly;
4599 /* Domains created from another domain already have application_base and configuration_file set */
4600 if (domain->setup->application_base == NULL) {
4601 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4604 if (domain->setup->configuration_file == NULL) {
4605 str = g_strconcat (assembly->image->name, ".config", NULL);
4606 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4608 mono_domain_set_options_from_config (domain);
4612 MonoError cattr_error;
4613 cinfo = mono_custom_attrs_from_method_checked (method, &cattr_error);
4614 mono_error_cleanup (&cattr_error); /* FIXME warn here? */
4616 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, mono_class_get_sta_thread_attribute_class ());
4618 mono_custom_attrs_free (cinfo);
4620 has_stathread_attribute = FALSE;
4622 if (has_stathread_attribute) {
4623 thread->apartment_state = ThreadApartmentState_STA;
4625 thread->apartment_state = ThreadApartmentState_MTA;
4627 mono_thread_init_apartment_state ();
4632 do_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4634 MONO_REQ_GC_UNSAFE_MODE;
4644 /* FIXME: check signature of method */
4645 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4647 res = mono_runtime_invoke_checked (method, NULL, pa, error);
4649 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4652 mono_environment_exitcode_set (rval);
4654 mono_runtime_invoke_checked (method, NULL, pa, error);
4666 do_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4668 MONO_REQ_GC_UNSAFE_MODE;
4678 /* FIXME: check signature of method */
4679 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4680 MonoError inner_error;
4682 res = mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4683 if (*exc == NULL && !mono_error_ok (&inner_error))
4684 *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4686 mono_error_cleanup (&inner_error);
4689 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4693 mono_environment_exitcode_set (rval);
4695 MonoError inner_error;
4696 mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4697 if (*exc == NULL && !mono_error_ok (&inner_error))
4698 *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4700 mono_error_cleanup (&inner_error);
4705 /* If the return type of Main is void, only
4706 * set the exitcode if an exception was thrown
4707 * (we don't want to blow away an
4708 * explicitly-set exit code)
4711 mono_environment_exitcode_set (rval);
4719 * Execute a standard Main() method (args doesn't contain the
4723 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4726 prepare_thread_to_exec_main (mono_object_domain (args), method);
4728 int rval = do_try_exec_main (method, args, exc);
4731 int rval = do_exec_main_checked (method, args, &error);
4732 mono_error_raise_exception (&error); /* OK to throw, external only with no better option */
4738 * Execute a standard Main() method (args doesn't contain the
4741 * On failure sets @error
4744 mono_runtime_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4747 prepare_thread_to_exec_main (mono_object_domain (args), method);
4748 return do_exec_main_checked (method, args, error);
4752 * Execute a standard Main() method (args doesn't contain the
4755 * On failure sets @error if Main couldn't be executed, or @exc if it threw an exception.
4758 mono_runtime_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4760 prepare_thread_to_exec_main (mono_object_domain (args), method);
4761 return do_try_exec_main (method, args, exc);
4766 /** invoke_array_extract_argument:
4767 * @params: array of arguments to the method.
4768 * @i: the index of the argument to extract.
4769 * @t: ith type from the method signature.
4770 * @has_byref_nullables: outarg - TRUE if method expects a byref nullable argument
4771 * @error: set on error.
4773 * Given an array of method arguments, return the ith one using the corresponding type
4774 * to perform necessary unboxing. If method expects a ref nullable argument, writes TRUE to @has_byref_nullables.
4776 * On failure sets @error and returns NULL.
4779 invoke_array_extract_argument (MonoArray *params, int i, MonoType *t, gboolean* has_byref_nullables, MonoError *error)
4781 MonoType *t_orig = t;
4782 gpointer result = NULL;
4788 case MONO_TYPE_BOOLEAN:
4791 case MONO_TYPE_CHAR:
4800 case MONO_TYPE_VALUETYPE:
4801 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (t_orig))) {
4802 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4803 result = mono_array_get (params, MonoObject*, i);
4805 *has_byref_nullables = TRUE;
4807 /* MS seems to create the objects if a null is passed in */
4808 gboolean was_null = FALSE;
4809 if (!mono_array_get (params, MonoObject*, i)) {
4810 MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (t_orig), error);
4811 return_val_if_nok (error, NULL);
4812 mono_array_setref (params, i, o);
4818 * We can't pass the unboxed vtype byref to the callee, since
4819 * that would mean the callee would be able to modify boxed
4820 * primitive types. So we (and MS) make a copy of the boxed
4821 * object, pass that to the callee, and replace the original
4822 * boxed object in the arg array with the copy.
4824 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4825 MonoObject *copy = mono_value_box_checked (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig), error);
4826 return_val_if_nok (error, NULL);
4827 mono_array_setref (params, i, copy);
4830 result = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4831 if (!t->byref && was_null)
4832 mono_array_setref (params, i, NULL);
4835 case MONO_TYPE_STRING:
4836 case MONO_TYPE_OBJECT:
4837 case MONO_TYPE_CLASS:
4838 case MONO_TYPE_ARRAY:
4839 case MONO_TYPE_SZARRAY:
4841 result = mono_array_addr (params, MonoObject*, i);
4842 // FIXME: I need to check this code path
4844 result = mono_array_get (params, MonoObject*, i);
4846 case MONO_TYPE_GENERICINST:
4848 t = &t->data.generic_class->container_class->this_arg;
4850 t = &t->data.generic_class->container_class->byval_arg;
4852 case MONO_TYPE_PTR: {
4855 /* The argument should be an IntPtr */
4856 arg = mono_array_get (params, MonoObject*, i);
4860 g_assert (arg->vtable->klass == mono_defaults.int_class);
4861 result = ((MonoIntPtr*)arg)->m_value;
4866 g_error ("type 0x%x not handled in mono_runtime_invoke_array", t_orig->type);
4871 * mono_runtime_invoke_array:
4872 * \param method method to invoke
4873 * \param obj object instance
4874 * \param params arguments to the method
4875 * \param exc exception information.
4876 * Invokes the method represented by \p method on the object \p obj.
4878 * \p obj is the \c this pointer, it should be NULL for static
4879 * methods, a \c MonoObject* for object instances and a pointer to
4880 * the value type for value types.
4882 * The \p params array contains the arguments to the method with the
4883 * same convention: \c MonoObject* pointers for object instances and
4884 * pointers to the value type otherwise. The \c _invoke_array
4885 * variant takes a C# \c object[] as the params argument (\c MonoArray*):
4886 * in this case the value types are boxed inside the
4887 * respective reference representation.
4889 * From unmanaged code you'll usually use the
4890 * mono_runtime_invoke_checked() variant.
4892 * Note that this function doesn't handle virtual methods for
4893 * you, it will exec the exact method you pass: we still need to
4894 * expose a function to lookup the derived class implementation
4895 * of a virtual method (there are examples of this in the code,
4898 * You can pass NULL as the \p exc argument if you don't want to
4899 * catch exceptions, otherwise, \c *exc will be set to the exception
4900 * thrown, if any. if an exception is thrown, you can't use the
4901 * \c MonoObject* result from the function.
4903 * If the method returns a value type, it is boxed in an object
4907 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4912 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, exc, &error);
4914 mono_error_cleanup (&error);
4917 if (!is_ok (&error))
4918 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
4922 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, NULL, &error);
4923 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
4929 * mono_runtime_invoke_array_checked:
4930 * \param method method to invoke
4931 * \param obj object instance
4932 * \param params arguments to the method
4933 * \param error set on failure.
4934 * Invokes the method represented by \p method on the object \p obj.
4936 * \p obj is the \c this pointer, it should be NULL for static
4937 * methods, a \c MonoObject* for object instances and a pointer to
4938 * the value type for value types.
4940 * The \p params array contains the arguments to the method with the
4941 * same convention: \c MonoObject* pointers for object instances and
4942 * pointers to the value type otherwise. The \c _invoke_array
4943 * variant takes a C# \c object[] as the \p params argument (\c MonoArray*):
4944 * in this case the value types are boxed inside the
4945 * respective reference representation.
4947 * From unmanaged code you'll usually use the
4948 * mono_runtime_invoke_checked() variant.
4950 * Note that this function doesn't handle virtual methods for
4951 * you, it will exec the exact method you pass: we still need to
4952 * expose a function to lookup the derived class implementation
4953 * of a virtual method (there are examples of this in the code,
4956 * On failure or exception, \p error will be set. In that case, you
4957 * can't use the \c MonoObject* result from the function.
4959 * If the method returns a value type, it is boxed in an object
4963 mono_runtime_invoke_array_checked (MonoMethod *method, void *obj, MonoArray *params,
4967 return mono_runtime_try_invoke_array (method, obj, params, NULL, error);
4971 * mono_runtime_try_invoke_array:
4972 * \param method method to invoke
4973 * \param obj object instance
4974 * \param params arguments to the method
4975 * \param exc exception information.
4976 * \param error set on failure.
4977 * Invokes the method represented by \p method on the object \p obj.
4979 * \p obj is the \c this pointer, it should be NULL for static
4980 * methods, a \c MonoObject* for object instances and a pointer to
4981 * the value type for value types.
4983 * The \p params array contains the arguments to the method with the
4984 * same convention: \c MonoObject* pointers for object instances and
4985 * pointers to the value type otherwise. The \c _invoke_array
4986 * variant takes a C# \c object[] as the params argument (\c MonoArray*):
4987 * in this case the value types are boxed inside the
4988 * respective reference representation.
4990 * From unmanaged code you'll usually use the
4991 * mono_runtime_invoke_checked() variant.
4993 * Note that this function doesn't handle virtual methods for
4994 * you, it will exec the exact method you pass: we still need to
4995 * expose a function to lookup the derived class implementation
4996 * of a virtual method (there are examples of this in the code,
4999 * You can pass NULL as the \p exc argument if you don't want to catch
5000 * exceptions, otherwise, \c *exc will be set to the exception thrown, if
5001 * any. On other failures, \p error will be set. If an exception is
5002 * thrown or there's an error, you can't use the \c MonoObject* result
5003 * from the function.
5005 * If the method returns a value type, it is boxed in an object
5009 mono_runtime_try_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
5010 MonoObject **exc, MonoError *error)
5012 MONO_REQ_GC_UNSAFE_MODE;
5016 MonoMethodSignature *sig = mono_method_signature (method);
5017 gpointer *pa = NULL;
5020 gboolean has_byref_nullables = FALSE;
5022 if (NULL != params) {
5023 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
5024 for (i = 0; i < mono_array_length (params); i++) {
5025 MonoType *t = sig->params [i];
5026 pa [i] = invoke_array_extract_argument (params, i, t, &has_byref_nullables, error);
5027 return_val_if_nok (error, NULL);
5031 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
5034 if (mono_class_is_nullable (method->klass)) {
5035 /* Need to create a boxed vtype instead */
5041 return mono_value_box_checked (mono_domain_get (), method->klass->cast_class, pa [0], error);
5046 obj = mono_object_new_checked (mono_domain_get (), method->klass, error);
5047 mono_error_assert_ok (error);
5048 g_assert (obj); /*maybe we should raise a TLE instead?*/
5049 #ifndef DISABLE_REMOTING
5050 if (mono_object_is_transparent_proxy (obj)) {
5051 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
5054 if (method->klass->valuetype)
5055 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
5058 } else if (method->klass->valuetype) {
5059 obj = mono_value_box_checked (mono_domain_get (), method->klass, obj, error);
5060 return_val_if_nok (error, NULL);
5064 mono_runtime_try_invoke (method, o, pa, exc, error);
5066 mono_runtime_invoke_checked (method, o, pa, error);
5069 return (MonoObject *)obj;
5071 if (mono_class_is_nullable (method->klass)) {
5072 MonoObject *nullable;
5074 /* Convert the unboxed vtype into a Nullable structure */
5075 nullable = mono_object_new_checked (mono_domain_get (), method->klass, error);
5076 return_val_if_nok (error, NULL);
5078 MonoObject *boxed = mono_value_box_checked (mono_domain_get (), method->klass->cast_class, obj, error);
5079 return_val_if_nok (error, NULL);
5080 mono_nullable_init ((guint8 *)mono_object_unbox (nullable), boxed, method->klass);
5081 obj = mono_object_unbox (nullable);
5084 /* obj must be already unboxed if needed */
5086 res = mono_runtime_try_invoke (method, obj, pa, exc, error);
5088 res = mono_runtime_invoke_checked (method, obj, pa, error);
5090 return_val_if_nok (error, NULL);
5092 if (sig->ret->type == MONO_TYPE_PTR) {
5093 MonoClass *pointer_class;
5094 static MonoMethod *box_method;
5096 MonoObject *box_exc;
5099 * The runtime-invoke wrapper returns a boxed IntPtr, need to
5100 * convert it to a Pointer object.
5102 pointer_class = mono_class_get_pointer_class ();
5104 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
5106 g_assert (res->vtable->klass == mono_defaults.int_class);
5107 box_args [0] = ((MonoIntPtr*)res)->m_value;
5108 box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, error);
5109 return_val_if_nok (error, NULL);
5111 res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, error);
5112 g_assert (box_exc == NULL);
5113 mono_error_assert_ok (error);
5116 if (has_byref_nullables) {
5118 * The runtime invoke wrapper already converted byref nullables back,
5119 * and stored them in pa, we just need to copy them back to the
5122 for (i = 0; i < mono_array_length (params); i++) {
5123 MonoType *t = sig->params [i];
5125 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
5126 mono_array_setref (params, i, pa [i]);
5136 * \param klass the class of the object that we want to create
5137 * \returns a newly created object whose definition is
5138 * looked up using \p klass. This will not invoke any constructors,
5139 * so the consumer of this routine has to invoke any constructors on
5140 * its own to initialize the object.
5142 * It returns NULL on failure.
5145 mono_object_new (MonoDomain *domain, MonoClass *klass)
5147 MONO_REQ_GC_UNSAFE_MODE;
5151 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5153 mono_error_cleanup (&error);
5158 ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
5160 MONO_REQ_GC_UNSAFE_MODE;
5164 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5166 mono_error_set_pending_exception (&error);
5171 * mono_object_new_checked:
5172 * \param klass the class of the object that we want to create
5173 * \param error set on error
5174 * \returns a newly created object whose definition is
5175 * looked up using \p klass. This will not invoke any constructors,
5176 * so the consumer of this routine has to invoke any constructors on
5177 * its own to initialize the object.
5179 * It returns NULL on failure and sets \p error.
5182 mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
5184 MONO_REQ_GC_UNSAFE_MODE;
5188 vtable = mono_class_vtable (domain, klass);
5189 g_assert (vtable); /* FIXME don't swallow the error */
5191 MonoObject *o = mono_object_new_specific_checked (vtable, error);
5196 * mono_object_new_pinned:
5198 * Same as mono_object_new, but the returned object will be pinned.
5199 * For SGEN, these objects will only be freed at appdomain unload.
5202 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
5204 MONO_REQ_GC_UNSAFE_MODE;
5210 vtable = mono_class_vtable (domain, klass);
5211 g_assert (vtable); /* FIXME don't swallow the error */
5213 MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
5215 if (G_UNLIKELY (!o))
5216 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
5217 else if (G_UNLIKELY (vtable->klass->has_finalize))
5218 mono_object_register_finalizer (o);
5224 * mono_object_new_specific:
5225 * \param vtable the vtable of the object that we want to create
5226 * \returns A newly created object with class and domain specified
5230 mono_object_new_specific (MonoVTable *vtable)
5233 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5234 mono_error_cleanup (&error);
5240 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
5242 MONO_REQ_GC_UNSAFE_MODE;
5248 /* check for is_com_object for COM Interop */
5249 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
5252 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
5255 MonoClass *klass = mono_class_get_activation_services_class ();
5258 mono_class_init (klass);
5260 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
5262 mono_error_set_not_supported (error, "Linked away.");
5265 vtable->domain->create_proxy_for_type_method = im;
5268 pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
5269 if (!mono_error_ok (error))
5272 o = mono_runtime_invoke_checked (im, NULL, pa, error);
5273 if (!mono_error_ok (error))
5280 return mono_object_new_alloc_specific_checked (vtable, error);
5284 ves_icall_object_new_specific (MonoVTable *vtable)
5287 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5288 mono_error_set_pending_exception (&error);
5294 * mono_object_new_alloc_specific:
5295 * \param vtable virtual table for the object.
5296 * This function allocates a new \c MonoObject with the type derived
5297 * from the \p vtable information. If the class of this object has a
5298 * finalizer, then the object will be tracked for finalization.
5300 * This method might raise an exception on errors. Use the
5301 * \c mono_object_new_fast_checked method if you want to manually raise
5304 * \returns the allocated object.
5307 mono_object_new_alloc_specific (MonoVTable *vtable)
5310 MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
5311 mono_error_cleanup (&error);
5317 * mono_object_new_alloc_specific_checked:
5318 * \param vtable virtual table for the object.
5319 * \param error holds the error return value.
5321 * This function allocates a new \c MonoObject with the type derived
5322 * from the \p vtable information. If the class of this object has a
5323 * finalizer, then the object will be tracked for finalization.
5325 * If there is not enough memory, the \p error parameter will be set
5326 * and will contain a user-visible message with the amount of bytes
5327 * that were requested.
5329 * \returns the allocated object, or NULL if there is not enough memory
5332 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
5334 MONO_REQ_GC_UNSAFE_MODE;
5340 o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5342 if (G_UNLIKELY (!o))
5343 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5344 else if (G_UNLIKELY (vtable->klass->has_finalize))
5345 mono_object_register_finalizer (o);
5351 * mono_object_new_fast:
5352 * \param vtable virtual table for the object.
5354 * This function allocates a new \c MonoObject with the type derived
5355 * from the \p vtable information. The returned object is not tracked
5356 * for finalization. If your object implements a finalizer, you should
5357 * use \c mono_object_new_alloc_specific instead.
5359 * This method might raise an exception on errors. Use the
5360 * \c mono_object_new_fast_checked method if you want to manually raise
5363 * \returns the allocated object.
5366 mono_object_new_fast (MonoVTable *vtable)
5369 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5370 mono_error_cleanup (&error);
5376 * mono_object_new_fast_checked:
5377 * \param vtable virtual table for the object.
5378 * \param error holds the error return value.
5380 * This function allocates a new \c MonoObject with the type derived
5381 * from the \p vtable information. The returned object is not tracked
5382 * for finalization. If your object implements a finalizer, you should
5383 * use \c mono_object_new_alloc_specific_checked instead.
5385 * If there is not enough memory, the \p error parameter will be set
5386 * and will contain a user-visible message with the amount of bytes
5387 * that were requested.
5389 * \returns the allocated object, or NULL if there is not enough memory
5392 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
5394 MONO_REQ_GC_UNSAFE_MODE;
5400 o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5402 if (G_UNLIKELY (!o))
5403 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5409 ves_icall_object_new_fast (MonoVTable *vtable)
5412 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5413 mono_error_set_pending_exception (&error);
5419 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
5421 MONO_REQ_GC_UNSAFE_MODE;
5427 o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
5429 if (G_UNLIKELY (!o))
5430 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5431 else if (G_UNLIKELY (vtable->klass->has_finalize))
5432 mono_object_register_finalizer (o);
5438 * mono_class_get_allocation_ftn:
5439 * \param vtable vtable
5440 * \param for_box the object will be used for boxing
5441 * \param pass_size_in_words Unused
5442 * \returns the allocation function appropriate for the given class.
5445 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
5447 MONO_REQ_GC_NEUTRAL_MODE;
5449 *pass_size_in_words = FALSE;
5451 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass))
5452 return ves_icall_object_new_specific;
5454 if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
5456 return ves_icall_object_new_fast;
5459 * FIXME: This is actually slower than ves_icall_object_new_fast, because
5460 * of the overhead of parameter passing.
5463 *pass_size_in_words = TRUE;
5464 #ifdef GC_REDIRECT_TO_LOCAL
5465 return GC_local_gcj_fast_malloc;
5467 return GC_gcj_fast_malloc;
5472 return ves_icall_object_new_specific;
5476 * mono_object_new_from_token:
5477 * \param image Context where the type_token is hosted
5478 * \param token a token of the type that we want to create
5479 * \returns A newly created object whose definition is
5480 * looked up using \p token in the \p image image
5483 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
5485 MONO_REQ_GC_UNSAFE_MODE;
5491 klass = mono_class_get_checked (image, token, &error);
5492 mono_error_assert_ok (&error);
5494 result = mono_object_new_checked (domain, klass, &error);
5496 mono_error_cleanup (&error);
5503 * mono_object_clone:
5504 * \param obj the object to clone
5505 * \returns A newly created object who is a shallow copy of \p obj
5508 mono_object_clone (MonoObject *obj)
5511 MonoObject *o = mono_object_clone_checked (obj, &error);
5512 mono_error_cleanup (&error);
5518 mono_object_clone_checked (MonoObject *obj, MonoError *error)
5520 MONO_REQ_GC_UNSAFE_MODE;
5527 size = obj->vtable->klass->instance_size;
5529 if (obj->vtable->klass->rank)
5530 return (MonoObject*)mono_array_clone_checked ((MonoArray*)obj, error);
5532 o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
5534 if (G_UNLIKELY (!o)) {
5535 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5539 /* If the object doesn't contain references this will do a simple memmove. */
5540 mono_gc_wbarrier_object_copy (o, obj);
5542 if (obj->vtable->klass->has_finalize)
5543 mono_object_register_finalizer (o);
5548 * mono_array_full_copy:
5549 * \param src source array to copy
5550 * \param dest destination array
5551 * Copies the content of one array to another with exactly the same type and size.
5554 mono_array_full_copy (MonoArray *src, MonoArray *dest)
5556 MONO_REQ_GC_UNSAFE_MODE;
5559 MonoClass *klass = src->obj.vtable->klass;
5561 g_assert (klass == dest->obj.vtable->klass);
5563 size = mono_array_length (src);
5564 g_assert (size == mono_array_length (dest));
5565 size *= mono_array_element_size (klass);
5567 array_full_copy_unchecked_size (src, dest, klass, size);
5571 array_full_copy_unchecked_size (MonoArray *src, MonoArray *dest, MonoClass *klass, uintptr_t size)
5574 if (klass->element_class->valuetype) {
5575 if (klass->element_class->has_references)
5576 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
5578 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5580 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
5583 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5588 * mono_array_clone_in_domain:
5589 * \param domain the domain in which the array will be cloned into
5590 * \param array the array to clone
5591 * \param error set on error
5592 * This routine returns a copy of the array that is hosted on the
5593 * specified \c MonoDomain. On failure returns NULL and sets \p error.
5596 mono_array_clone_in_domain (MonoDomain *domain, MonoArrayHandle array_handle, MonoError *error)
5598 MONO_REQ_GC_UNSAFE_MODE;
5600 MonoArrayHandle result = MONO_HANDLE_NEW (MonoArray, NULL);
5602 MonoClass *klass = mono_handle_class (array_handle);
5606 /* Pin source array here - if bounds is non-NULL, it's a pointer into the object data */
5607 uint32_t src_handle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, array_handle), TRUE);
5609 MonoArrayBounds *array_bounds = MONO_HANDLE_GETVAL (array_handle, bounds);
5611 if (array_bounds == NULL) {
5612 size = mono_array_handle_length (array_handle);
5613 o = mono_array_new_full_handle (domain, klass, &size, NULL, error);
5616 size *= mono_array_element_size (klass);
5618 uintptr_t *sizes = (uintptr_t *)alloca (klass->rank * sizeof (uintptr_t));
5619 intptr_t *lower_bounds = (intptr_t *)alloca (klass->rank * sizeof (intptr_t));
5620 size = mono_array_element_size (klass);
5621 for (int i = 0; i < klass->rank; ++i) {
5622 sizes [i] = array_bounds [i].length;
5623 size *= array_bounds [i].length;
5624 lower_bounds [i] = array_bounds [i].lower_bound;
5626 o = mono_array_new_full_handle (domain, klass, sizes, lower_bounds, error);
5631 uint32_t dst_handle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, o), TRUE);
5632 array_full_copy_unchecked_size (MONO_HANDLE_RAW (array_handle), MONO_HANDLE_RAW (o), klass, size);
5633 mono_gchandle_free (dst_handle);
5635 MONO_HANDLE_ASSIGN (result, o);
5638 mono_gchandle_free (src_handle);
5644 * \param array the array to clone
5645 * \returns A newly created array who is a shallow copy of \p array
5648 mono_array_clone (MonoArray *array)
5650 MONO_REQ_GC_UNSAFE_MODE;
5653 MonoArray *result = mono_array_clone_checked (array, &error);
5654 mono_error_cleanup (&error);
5659 * mono_array_clone_checked:
5660 * \param array the array to clone
5661 * \param error set on error
5662 * \returns A newly created array who is a shallow copy of \p array. On
5663 * failure returns NULL and sets \p error.
5666 mono_array_clone_checked (MonoArray *array_raw, MonoError *error)
5668 MONO_REQ_GC_UNSAFE_MODE;
5669 HANDLE_FUNCTION_ENTER ();
5670 /* FIXME: callers of mono_array_clone_checked should use handles */
5672 MONO_HANDLE_DCL (MonoArray, array);
5673 MonoArrayHandle result = mono_array_clone_in_domain (MONO_HANDLE_DOMAIN (array), array, error);
5674 HANDLE_FUNCTION_RETURN_OBJ (result);
5677 /* helper macros to check for overflow when calculating the size of arrays */
5678 #ifdef MONO_BIG_ARRAYS
5679 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
5680 #define MYGUINT_MAX MYGUINT64_MAX
5681 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5682 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
5683 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5684 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
5685 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
5687 #define MYGUINT32_MAX 4294967295U
5688 #define MYGUINT_MAX MYGUINT32_MAX
5689 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5690 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
5691 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5692 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
5693 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
5697 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
5699 MONO_REQ_GC_NEUTRAL_MODE;
5703 byte_len = mono_array_element_size (klass);
5704 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
5707 if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
5709 byte_len += MONO_SIZEOF_MONO_ARRAY;
5717 * mono_array_new_full:
5718 * \param domain domain where the object is created
5719 * \param array_class array class
5720 * \param lengths lengths for each dimension in the array
5721 * \param lower_bounds lower bounds for each dimension in the array (may be NULL)
5722 * This routine creates a new array object with the given dimensions,
5723 * lower bounds and type.
5726 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
5729 MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
5730 mono_error_cleanup (&error);
5736 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
5738 MONO_REQ_GC_UNSAFE_MODE;
5740 uintptr_t byte_len = 0, len, bounds_size;
5743 MonoArrayBounds *bounds;
5749 if (!array_class->inited)
5750 mono_class_init (array_class);
5754 /* A single dimensional array with a 0 lower bound is the same as an szarray */
5755 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
5757 if (len > MONO_ARRAY_MAX_INDEX) {
5758 mono_error_set_generic_error (error, "System", "OverflowException", "");
5763 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
5765 for (i = 0; i < array_class->rank; ++i) {
5766 if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
5767 mono_error_set_generic_error (error, "System", "OverflowException", "");
5770 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5771 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5778 if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5779 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5785 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5786 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5789 byte_len = (byte_len + 3) & ~3;
5790 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5791 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5794 byte_len += bounds_size;
5797 * Following three lines almost taken from mono_object_new ():
5798 * they need to be kept in sync.
5800 vtable = mono_class_vtable_full (domain, array_class, error);
5801 return_val_if_nok (error, NULL);
5804 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5806 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5808 if (G_UNLIKELY (!o)) {
5809 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5813 array = (MonoArray*)o;
5815 bounds = array->bounds;
5818 for (i = 0; i < array_class->rank; ++i) {
5819 bounds [i].length = lengths [i];
5821 bounds [i].lower_bound = lower_bounds [i];
5830 * \param domain domain where the object is created
5831 * \param eclass element class
5832 * \param n number of array elements
5833 * This routine creates a new szarray with \p n elements of type \p eclass.
5836 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5838 MONO_REQ_GC_UNSAFE_MODE;
5841 MonoArray *result = mono_array_new_checked (domain, eclass, n, &error);
5842 mono_error_cleanup (&error);
5847 * mono_array_new_checked:
5848 * \param domain domain where the object is created
5849 * \param eclass element class
5850 * \param n number of array elements
5851 * \param error set on error
5852 * This routine creates a new szarray with \p n elements of type \p eclass.
5853 * On failure returns NULL and sets \p error.
5856 mono_array_new_checked (MonoDomain *domain, MonoClass *eclass, uintptr_t n, MonoError *error)
5862 ac = mono_array_class_get (eclass, 1);
5865 MonoVTable *vtable = mono_class_vtable_full (domain, ac, error);
5866 return_val_if_nok (error, NULL);
5868 return mono_array_new_specific_checked (vtable, n, error);
5872 ves_icall_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5875 MonoArray *arr = mono_array_new_checked (domain, eclass, n, &error);
5876 mono_error_set_pending_exception (&error);
5882 * mono_array_new_specific:
5883 * \param vtable a vtable in the appropriate domain for an initialized class
5884 * \param n number of array elements
5885 * This routine is a fast alternative to \c mono_array_new for code which
5886 * can be sure about the domain it operates in.
5889 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5892 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5893 mono_error_cleanup (&error);
5899 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
5901 MONO_REQ_GC_UNSAFE_MODE;
5908 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
5909 mono_error_set_generic_error (error, "System", "OverflowException", "");
5913 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
5914 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5917 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
5919 if (G_UNLIKELY (!o)) {
5920 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5924 return (MonoArray*)o;
5928 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
5931 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5932 mono_error_set_pending_exception (&error);
5938 * mono_string_empty_wrapper:
5940 * Returns: The same empty string instance as the managed string.Empty
5943 mono_string_empty_wrapper (void)
5945 MonoDomain *domain = mono_domain_get ();
5946 return mono_string_empty (domain);
5950 * mono_string_empty:
5952 * Returns: The same empty string instance as the managed string.Empty
5955 mono_string_empty (MonoDomain *domain)
5958 g_assert (domain->empty_string);
5959 return domain->empty_string;
5963 * mono_string_new_utf16:
5964 * \param text a pointer to an utf16 string
5965 * \param len the length of the string
5966 * \returns A newly created string object which contains \p text.
5969 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
5971 MONO_REQ_GC_UNSAFE_MODE;
5974 MonoString *res = NULL;
5975 res = mono_string_new_utf16_checked (domain, text, len, &error);
5976 mono_error_cleanup (&error);
5982 * mono_string_new_utf16_checked:
5983 * \param text a pointer to an utf16 string
5984 * \param len the length of the string
5985 * \param error written on error.
5986 * \returns A newly created string object which contains \p text.
5987 * On error, returns NULL and sets \p error.
5990 mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
5992 MONO_REQ_GC_UNSAFE_MODE;
5998 s = mono_string_new_size_checked (domain, len, error);
6000 memcpy (mono_string_chars (s), text, len * 2);
6006 * mono_string_new_utf16_handle:
6007 * \param text a pointer to an utf16 string
6008 * \param len the length of the string
6009 * \param error written on error.
6010 * \returns A newly created string object which contains \p text.
6011 * On error, returns NULL and sets \p error.
6014 mono_string_new_utf16_handle (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
6016 return MONO_HANDLE_NEW (MonoString, mono_string_new_utf16_checked (domain, text, len, error));
6020 * mono_string_new_utf32_checked:
6021 * \param text a pointer to an utf32 string
6022 * \param len the length of the string
6023 * \param error set on failure.
6024 * \returns A newly created string object which contains \p text. On failure returns NULL and sets \p error.
6027 mono_string_new_utf32_checked (MonoDomain *domain, const mono_unichar4 *text, gint32 len, MonoError *error)
6029 MONO_REQ_GC_UNSAFE_MODE;
6032 mono_unichar2 *utf16_output = NULL;
6033 gint32 utf16_len = 0;
6034 GError *gerror = NULL;
6035 glong items_written;
6038 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
6041 g_error_free (gerror);
6043 while (utf16_output [utf16_len]) utf16_len++;
6045 s = mono_string_new_size_checked (domain, utf16_len, error);
6046 return_val_if_nok (error, NULL);
6048 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
6050 g_free (utf16_output);
6056 * mono_string_new_utf32:
6057 * \param text a pointer to a UTF-32 string
6058 * \param len the length of the string
6059 * \returns A newly created string object which contains \p text.
6062 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
6065 MonoString *result = mono_string_new_utf32_checked (domain, text, len, &error);
6066 mono_error_cleanup (&error);
6071 * mono_string_new_size:
6072 * \param text a pointer to a UTF-16 string
6073 * \param len the length of the string
6074 * \returns A newly created string object of \p len
6077 mono_string_new_size (MonoDomain *domain, gint32 len)
6080 MonoString *str = mono_string_new_size_checked (domain, len, &error);
6081 mono_error_cleanup (&error);
6087 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
6089 MONO_REQ_GC_UNSAFE_MODE;
6097 /* check for overflow */
6098 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
6099 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
6103 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
6104 g_assert (size > 0);
6106 vtable = mono_class_vtable (domain, mono_defaults.string_class);
6109 s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
6111 if (G_UNLIKELY (!s)) {
6112 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", size);
6120 * mono_string_new_len:
6121 * \param text a pointer to an utf8 string
6122 * \param length number of bytes in \p text to consider
6123 * \returns A newly created string object which contains \p text.
6126 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
6128 MONO_REQ_GC_UNSAFE_MODE;
6131 MonoString *result = mono_string_new_len_checked (domain, text, length, &error);
6132 mono_error_cleanup (&error);
6137 * mono_string_new_len_checked:
6138 * \param text a pointer to an utf8 string
6139 * \param length number of bytes in \p text to consider
6140 * \param error set on error
6141 * \returns A newly created string object which contains \p text. On
6142 * failure returns NULL and sets \p error.
6145 mono_string_new_len_checked (MonoDomain *domain, const char *text, guint length, MonoError *error)
6147 MONO_REQ_GC_UNSAFE_MODE;
6151 GError *eg_error = NULL;
6152 MonoString *o = NULL;
6154 glong items_written;
6156 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
6159 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6161 g_error_free (eg_error);
6170 * \param text a pointer to a UTF-8 string
6171 * \deprecated Use \c mono_string_new_checked in new code.
6172 * This function asserts if it cannot allocate a new string.
6173 * \returns A newly created string object which contains \p text.
6176 mono_string_new (MonoDomain *domain, const char *text)
6179 MonoString *res = NULL;
6180 res = mono_string_new_checked (domain, text, &error);
6181 mono_error_assert_ok (&error);
6186 * mono_string_new_checked:
6187 * \param text a pointer to an utf8 string
6188 * \param merror set on error
6189 * \returns A newly created string object which contains \p text.
6190 * On error returns NULL and sets \p merror.
6193 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
6195 MONO_REQ_GC_UNSAFE_MODE;
6197 GError *eg_error = NULL;
6198 MonoString *o = NULL;
6200 glong items_written;
6207 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &eg_error);
6210 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6212 mono_error_set_execution_engine (error, "String conversion error: %s", eg_error->message);
6217 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
6222 MonoString *o = NULL;
6224 if (!g_utf8_validate (text, -1, &end)) {
6225 mono_error_set_argument (error, "text", "Not a valid utf8 string");
6229 len = g_utf8_strlen (text, -1);
6230 o = mono_string_new_size_checked (domain, len, error);
6233 str = mono_string_chars (o);
6235 while (text < end) {
6236 *str++ = g_utf8_get_char (text);
6237 text = g_utf8_next_char (text);
6246 * mono_string_new_wrapper:
6247 * \param text pointer to UTF-8 characters.
6248 * Helper function to create a string object from \p text in the current domain.
6251 mono_string_new_wrapper (const char *text)
6253 MONO_REQ_GC_UNSAFE_MODE;
6255 MonoDomain *domain = mono_domain_get ();
6258 return mono_string_new (domain, text);
6265 * \param class the class of the value
6266 * \param value a pointer to the unboxed data
6267 * \returns A newly created object which contains \p value.
6270 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
6273 MonoObject *result = mono_value_box_checked (domain, klass, value, &error);
6274 mono_error_cleanup (&error);
6279 * mono_value_box_checked:
6280 * \param domain the domain of the new object
6281 * \param class the class of the value
6282 * \param value a pointer to the unboxed data
6283 * \param error set on error
6284 * \returns A newly created object which contains \p value. On failure
6285 * returns NULL and sets \p error.
6288 mono_value_box_checked (MonoDomain *domain, MonoClass *klass, gpointer value, MonoError *error)
6290 MONO_REQ_GC_UNSAFE_MODE;
6297 g_assert (klass->valuetype);
6298 if (mono_class_is_nullable (klass))
6299 return mono_nullable_box ((guint8 *)value, klass, error);
6301 vtable = mono_class_vtable (domain, klass);
6304 size = mono_class_instance_size (klass);
6305 res = mono_object_new_alloc_specific_checked (vtable, error);
6306 return_val_if_nok (error, NULL);
6308 size = size - sizeof (MonoObject);
6311 g_assert (size == mono_class_value_size (klass, NULL));
6312 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
6314 #if NO_UNALIGNED_ACCESS
6315 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6319 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
6322 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
6325 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
6328 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
6331 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6335 if (klass->has_finalize) {
6336 mono_object_register_finalizer (res);
6337 return_val_if_nok (error, NULL);
6344 * \param dest destination pointer
6345 * \param src source pointer
6346 * \param klass a valuetype class
6347 * Copy a valuetype from \p src to \p dest. This function must be used
6348 * when \p klass contains reference fields.
6351 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
6353 MONO_REQ_GC_UNSAFE_MODE;
6355 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
6359 * mono_value_copy_array:
6360 * \param dest destination array
6361 * \param dest_idx index in the \p dest array
6362 * \param src source pointer
6363 * \param count number of items
6364 * Copy \p count valuetype items from \p src to the array \p dest at index \p dest_idx.
6365 * This function must be used when \p klass contains references fields.
6366 * Overlap is handled.
6369 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
6371 MONO_REQ_GC_UNSAFE_MODE;
6373 int size = mono_array_element_size (dest->obj.vtable->klass);
6374 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
6375 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
6376 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
6380 * mono_object_get_domain:
6381 * \param obj object to query
6382 * \returns the \c MonoDomain where the object is hosted
6385 mono_object_get_domain (MonoObject *obj)
6387 MONO_REQ_GC_UNSAFE_MODE;
6389 return mono_object_domain (obj);
6393 * mono_object_get_class:
6394 * \param obj object to query
6395 * Use this function to obtain the \c MonoClass* for a given \c MonoObject.
6396 * \returns the \c MonoClass of the object.
6399 mono_object_get_class (MonoObject *obj)
6401 MONO_REQ_GC_UNSAFE_MODE;
6403 return mono_object_class (obj);
6406 * mono_object_get_size:
6407 * \param o object to query
6408 * \returns the size, in bytes, of \p o
6411 mono_object_get_size (MonoObject* o)
6413 MONO_REQ_GC_UNSAFE_MODE;
6415 MonoClass* klass = mono_object_class (o);
6416 if (klass == mono_defaults.string_class) {
6417 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
6418 } else if (o->vtable->rank) {
6419 MonoArray *array = (MonoArray*)o;
6420 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
6421 if (array->bounds) {
6424 size += sizeof (MonoArrayBounds) * o->vtable->rank;
6428 return mono_class_instance_size (klass);
6433 * mono_object_unbox:
6434 * \param obj object to unbox
6435 * \returns a pointer to the start of the valuetype boxed in this
6438 * This method will assert if the object passed is not a valuetype.
6441 mono_object_unbox (MonoObject *obj)
6443 MONO_REQ_GC_UNSAFE_MODE;
6445 /* add assert for valuetypes? */
6446 g_assert (obj->vtable->klass->valuetype);
6447 return ((char*)obj) + sizeof (MonoObject);
6451 * mono_object_isinst:
6452 * \param obj an object
6453 * \param klass a pointer to a class
6454 * \returns \p obj if \p obj is derived from \p klass or NULL otherwise.
6457 mono_object_isinst (MonoObject *obj_raw, MonoClass *klass)
6459 MONO_REQ_GC_UNSAFE_MODE;
6461 HANDLE_FUNCTION_ENTER ();
6462 MONO_HANDLE_DCL (MonoObject, obj);
6464 MonoObjectHandle result = mono_object_handle_isinst (obj, klass, &error);
6465 mono_error_cleanup (&error);
6466 HANDLE_FUNCTION_RETURN_OBJ (result);
6471 * mono_object_isinst_checked:
6472 * \param obj an object
6473 * \param klass a pointer to a class
6474 * \param error set on error
6475 * \returns \p obj if \p obj is derived from \p klass or NULL if it isn't.
6476 * On failure returns NULL and sets \p error.
6479 mono_object_isinst_checked (MonoObject *obj_raw, MonoClass *klass, MonoError *error)
6481 MONO_REQ_GC_UNSAFE_MODE;
6483 HANDLE_FUNCTION_ENTER ();
6485 MONO_HANDLE_DCL (MonoObject, obj);
6486 MonoObjectHandle result = mono_object_handle_isinst (obj, klass, error);
6487 HANDLE_FUNCTION_RETURN_OBJ (result);
6491 * mono_object_handle_isinst:
6492 * \param obj an object
6493 * \param klass a pointer to a class
6494 * \param error set on error
6495 * \returns \p obj if \p obj is derived from \p klass or NULL if it isn't.
6496 * On failure returns NULL and sets \p error.
6499 mono_object_handle_isinst (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
6504 mono_class_init (klass);
6506 if (mono_class_is_marshalbyref (klass) || mono_class_is_interface (klass)) {
6507 return mono_object_handle_isinst_mbyref (obj, klass, error);
6510 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6512 if (!MONO_HANDLE_IS_NULL (obj) && mono_class_is_assignable_from (klass, mono_handle_class (obj)))
6513 MONO_HANDLE_ASSIGN (result, obj);
6518 * mono_object_isinst_mbyref:
6521 mono_object_isinst_mbyref (MonoObject *obj_raw, MonoClass *klass)
6523 MONO_REQ_GC_UNSAFE_MODE;
6525 HANDLE_FUNCTION_ENTER ();
6527 MONO_HANDLE_DCL (MonoObject, obj);
6528 MonoObjectHandle result = mono_object_handle_isinst_mbyref (obj, klass, &error);
6529 mono_error_cleanup (&error); /* FIXME better API that doesn't swallow the error */
6530 HANDLE_FUNCTION_RETURN_OBJ (result);
6534 mono_object_handle_isinst_mbyref (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
6538 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6540 if (MONO_HANDLE_IS_NULL (obj))
6543 MonoVTable *vt = MONO_HANDLE_GETVAL (obj, vtable);
6545 if (mono_class_is_interface (klass)) {
6546 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
6547 MONO_HANDLE_ASSIGN (result, obj);
6551 /* casting an array one of the invariant interfaces that must act as such */
6552 if (klass->is_array_special_interface) {
6553 if (mono_class_is_assignable_from (klass, vt->klass)) {
6554 MONO_HANDLE_ASSIGN (result, obj);
6559 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
6560 else if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, mono_handle_class (obj))) {
6561 MONO_HANDLE_ASSIGN (result, obj);
6565 MonoClass *oklass = vt->klass;
6566 if (mono_class_is_transparent_proxy (oklass)){
6567 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), remote_class);
6568 oklass = remote_class->proxy_class;
6571 mono_class_setup_supertypes (klass);
6572 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass)) {
6573 MONO_HANDLE_ASSIGN (result, obj);
6577 #ifndef DISABLE_REMOTING
6578 if (mono_class_is_transparent_proxy (vt->klass))
6580 MonoBoolean custom_type_info = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), custom_type_info);
6581 if (!custom_type_info)
6583 MonoDomain *domain = mono_domain_get ();
6584 MonoObjectHandle rp = MONO_HANDLE_NEW (MonoObject, NULL);
6585 MONO_HANDLE_GET (rp, MONO_HANDLE_CAST (MonoTransparentProxy, obj), rp);
6586 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
6587 MonoMethod *im = NULL;
6590 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
6592 mono_error_set_not_supported (error, "Linked away.");
6595 im = mono_object_handle_get_virtual_method (rp, im, error);
6600 MonoReflectionTypeHandle reftype = mono_type_get_object_handle (domain, &klass->byval_arg, error);
6604 pa [0] = MONO_HANDLE_RAW (reftype);
6605 pa [1] = MONO_HANDLE_RAW (obj);
6606 MonoObject *res = mono_runtime_invoke_checked (im, MONO_HANDLE_RAW (rp), pa, error);
6610 if (*(MonoBoolean *) mono_object_unbox(res)) {
6611 /* Update the vtable of the remote type, so it can safely cast to this new type */
6612 mono_upgrade_remote_class (domain, obj, klass, error);
6615 MONO_HANDLE_ASSIGN (result, obj);
6618 #endif /* DISABLE_REMOTING */
6624 * mono_object_castclass_mbyref:
6625 * \param obj an object
6626 * \param klass a pointer to a class
6627 * \returns \p obj if \p obj is derived from \p klass, returns NULL otherwise.
6630 mono_object_castclass_mbyref (MonoObject *obj_raw, MonoClass *klass)
6632 MONO_REQ_GC_UNSAFE_MODE;
6633 HANDLE_FUNCTION_ENTER ();
6635 MONO_HANDLE_DCL (MonoObject, obj);
6636 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6637 if (MONO_HANDLE_IS_NULL (obj))
6639 MONO_HANDLE_ASSIGN (result, mono_object_handle_isinst_mbyref (obj, klass, &error));
6640 mono_error_cleanup (&error);
6642 HANDLE_FUNCTION_RETURN_OBJ (result);
6646 MonoDomain *orig_domain;
6652 str_lookup (MonoDomain *domain, gpointer user_data)
6654 MONO_REQ_GC_UNSAFE_MODE;
6656 LDStrInfo *info = (LDStrInfo *)user_data;
6657 if (info->res || domain == info->orig_domain)
6659 info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
6663 mono_string_get_pinned (MonoString *str, MonoError *error)
6665 MONO_REQ_GC_UNSAFE_MODE;
6669 /* We only need to make a pinned version of a string if this is a moving GC */
6670 if (!mono_gc_is_moving ())
6674 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
6675 news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
6677 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
6678 news->length = mono_string_length (str);
6680 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6686 mono_string_is_interned_lookup (MonoString *str, int insert, MonoError *error)
6688 MONO_REQ_GC_UNSAFE_MODE;
6690 MonoGHashTable *ldstr_table;
6691 MonoString *s, *res;
6696 domain = ((MonoObject *)str)->vtable->domain;
6697 ldstr_table = domain->ldstr_table;
6699 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6705 /* Allocate outside the lock */
6707 s = mono_string_get_pinned (str, error);
6708 return_val_if_nok (error, NULL);
6711 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6716 mono_g_hash_table_insert (ldstr_table, s, s);
6721 LDStrInfo ldstr_info;
6722 ldstr_info.orig_domain = domain;
6723 ldstr_info.ins = str;
6724 ldstr_info.res = NULL;
6726 mono_domain_foreach (str_lookup, &ldstr_info);
6727 if (ldstr_info.res) {
6729 * the string was already interned in some other domain:
6730 * intern it in the current one as well.
6732 mono_g_hash_table_insert (ldstr_table, str, str);
6742 * mono_string_is_interned:
6743 * \param o String to probe
6744 * \returns Whether the string has been interned.
6747 mono_string_is_interned (MonoString *o)
6750 MonoString *result = mono_string_is_interned_lookup (o, FALSE, &error);
6751 /* This function does not fail. */
6752 mono_error_assert_ok (&error);
6757 * mono_string_intern:
6758 * \param o String to intern
6759 * Interns the string passed.
6760 * \returns The interned string.
6763 mono_string_intern (MonoString *str)
6766 MonoString *result = mono_string_intern_checked (str, &error);
6767 mono_error_assert_ok (&error);
6772 * mono_string_intern_checked:
6773 * \param o String to intern
6774 * \param error set on error.
6775 * Interns the string passed.
6776 * \returns The interned string. On failure returns NULL and sets \p error
6779 mono_string_intern_checked (MonoString *str, MonoError *error)
6781 MONO_REQ_GC_UNSAFE_MODE;
6785 return mono_string_is_interned_lookup (str, TRUE, error);
6790 * \param domain the domain where the string will be used.
6791 * \param image a metadata context
6792 * \param idx index into the user string table.
6793 * Implementation for the \c ldstr opcode.
6794 * \returns a loaded string from the \p image / \p idx combination.
6797 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
6800 MonoString *result = mono_ldstr_checked (domain, image, idx, &error);
6801 mono_error_cleanup (&error);
6806 * mono_ldstr_checked:
6807 * \param domain the domain where the string will be used.
6808 * \param image a metadata context
6809 * \param idx index into the user string table.
6810 * \param error set on error.
6811 * Implementation for the \c ldstr opcode.
6812 * \returns A loaded string from the \p image / \p idx combination.
6813 * On failure returns NULL and sets \p error.
6816 mono_ldstr_checked (MonoDomain *domain, MonoImage *image, guint32 idx, MonoError *error)
6818 MONO_REQ_GC_UNSAFE_MODE;
6821 if (image->dynamic) {
6822 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL, error);
6825 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6826 return NULL; /*FIXME we should probably be raising an exception here*/
6827 MonoString *str = mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx), error);
6833 * mono_ldstr_metadata_sig
6834 * \param domain the domain for the string
6835 * \param sig the signature of a metadata string
6836 * \param error set on error
6837 * \returns a \c MonoString for a string stored in the metadata. On
6838 * failure returns NULL and sets \p error.
6841 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error)
6843 MONO_REQ_GC_UNSAFE_MODE;
6846 const char *str = sig;
6847 MonoString *o, *interned;
6850 len2 = mono_metadata_decode_blob_size (str, &str);
6853 o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, error);
6854 return_val_if_nok (error, NULL);
6855 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
6858 guint16 *p2 = (guint16*)mono_string_chars (o);
6859 for (i = 0; i < len2; ++i) {
6860 *p2 = GUINT16_FROM_LE (*p2);
6866 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6869 return interned; /* o will get garbage collected */
6871 o = mono_string_get_pinned (o, error);
6874 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6876 mono_g_hash_table_insert (domain->ldstr_table, o, o);
6888 * Same as mono_ldstr, but return a NULL terminated utf8 string instead
6892 mono_ldstr_utf8 (MonoImage *image, guint32 idx, MonoError *error)
6898 GError *gerror = NULL;
6902 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6903 return NULL; /*FIXME we should probably be raising an exception here*/
6904 str = mono_metadata_user_string (image, idx);
6906 len2 = mono_metadata_decode_blob_size (str, &str);
6909 as = g_utf16_to_utf8 ((guint16*)str, len2, NULL, &written, &gerror);
6911 mono_error_set_argument (error, "string", "%s", gerror->message);
6912 g_error_free (gerror);
6915 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6916 if (len2 > written) {
6917 /* allocate the total length and copy the part of the string that has been converted */
6918 char *as2 = (char *)g_malloc0 (len2);
6919 memcpy (as2, as, written);
6928 * mono_string_to_utf8:
6929 * \param s a \c System.String
6930 * \deprecated Use \c mono_string_to_utf8_checked to avoid having an exception arbitrarily raised.
6931 * \returns the UTF-8 representation for \p s.
6932 * The resulting buffer needs to be freed with \c mono_free().
6935 mono_string_to_utf8 (MonoString *s)
6937 MONO_REQ_GC_UNSAFE_MODE;
6940 char *result = mono_string_to_utf8_checked (s, &error);
6942 if (!is_ok (&error)) {
6943 mono_error_cleanup (&error);
6950 * mono_string_to_utf8_checked:
6951 * \param s a \c System.String
6952 * \param error a \c MonoError.
6953 * Converts a \c MonoString to its UTF-8 representation. May fail; check
6954 * \p error to determine whether the conversion was successful.
6955 * The resulting buffer should be freed with \c mono_free().
6958 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
6960 MONO_REQ_GC_UNSAFE_MODE;
6964 GError *gerror = NULL;
6972 return g_strdup ("");
6974 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
6976 mono_error_set_argument (error, "string", "%s", gerror->message);
6977 g_error_free (gerror);
6980 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6981 if (s->length > written) {
6982 /* allocate the total length and copy the part of the string that has been converted */
6983 char *as2 = (char *)g_malloc0 (s->length);
6984 memcpy (as2, as, written);
6993 mono_string_handle_to_utf8 (MonoStringHandle s, MonoError *error)
6995 return mono_string_to_utf8_checked (MONO_HANDLE_RAW (s), error);
6999 * mono_string_to_utf8_ignore:
7000 * \param s a MonoString
7001 * Converts a \c MonoString to its UTF-8 representation. Will ignore
7002 * invalid surrogate pairs.
7003 * The resulting buffer should be freed with \c mono_free().
7006 mono_string_to_utf8_ignore (MonoString *s)
7008 MONO_REQ_GC_UNSAFE_MODE;
7017 return g_strdup ("");
7019 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
7021 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
7022 if (s->length > written) {
7023 /* allocate the total length and copy the part of the string that has been converted */
7024 char *as2 = (char *)g_malloc0 (s->length);
7025 memcpy (as2, as, written);
7034 * mono_string_to_utf8_image_ignore:
7035 * \param s a \c System.String
7036 * Same as \c mono_string_to_utf8_ignore, but allocate the string from the image mempool.
7039 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
7041 MONO_REQ_GC_UNSAFE_MODE;
7043 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
7047 * mono_string_to_utf8_mp_ignore:
7048 * \param s a \c System.String
7049 * Same as \c mono_string_to_utf8_ignore, but allocate the string from a mempool.
7052 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
7054 MONO_REQ_GC_UNSAFE_MODE;
7056 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
7061 * mono_string_to_utf16:
7062 * \param s a \c MonoString
7063 * \returns a null-terminated array of the UTF-16 chars
7064 * contained in \p s. The result must be freed with \c g_free().
7065 * This is a temporary helper until our string implementation
7066 * is reworked to always include the null-terminating char.
7069 mono_string_to_utf16 (MonoString *s)
7071 MONO_REQ_GC_UNSAFE_MODE;
7078 as = (char *)g_malloc ((s->length * 2) + 2);
7079 as [(s->length * 2)] = '\0';
7080 as [(s->length * 2) + 1] = '\0';
7083 return (gunichar2 *)(as);
7086 memcpy (as, mono_string_chars(s), s->length * 2);
7087 return (gunichar2 *)(as);
7091 * mono_string_to_utf32:
7092 * \param s a \c MonoString
7093 * \returns a null-terminated array of the UTF-32 (UCS-4) chars
7094 * contained in \p s. The result must be freed with \c g_free().
7097 mono_string_to_utf32 (MonoString *s)
7099 MONO_REQ_GC_UNSAFE_MODE;
7101 mono_unichar4 *utf32_output = NULL;
7102 GError *error = NULL;
7103 glong items_written;
7108 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
7111 g_error_free (error);
7113 return utf32_output;
7117 * mono_string_from_utf16:
7118 * \param data the UTF-16 string (LPWSTR) to convert
7119 * Converts a NULL-terminated UTF-16 string (LPWSTR) to a \c MonoString.
7120 * \returns a \c MonoString.
7123 mono_string_from_utf16 (gunichar2 *data)
7126 MonoString *result = mono_string_from_utf16_checked (data, &error);
7127 mono_error_cleanup (&error);
7132 * mono_string_from_utf16_checked:
7133 * \param data the UTF-16 string (LPWSTR) to convert
7134 * \param error set on error
7135 * Converts a NULL-terminated UTF-16 string (LPWSTR) to a \c MonoString.
7136 * \returns a \c MonoString. On failure sets \p error and returns NULL.
7139 mono_string_from_utf16_checked (gunichar2 *data, MonoError *error)
7142 MONO_REQ_GC_UNSAFE_MODE;
7145 MonoDomain *domain = mono_domain_get ();
7151 while (data [len]) len++;
7153 return mono_string_new_utf16_checked (domain, data, len, error);
7157 * mono_string_from_utf32:
7158 * \param data the UTF-32 string (LPWSTR) to convert
7159 * Converts a UTF-32 (UCS-4) string to a \c MonoString.
7160 * \returns a \c MonoString.
7163 mono_string_from_utf32 (mono_unichar4 *data)
7166 MonoString *result = mono_string_from_utf32_checked (data, &error);
7167 mono_error_cleanup (&error);
7172 * mono_string_from_utf32_checked:
7173 * \param data the UTF-32 string (LPWSTR) to convert
7174 * \param error set on error
7175 * Converts a UTF-32 (UCS-4) string to a \c MonoString.
7176 * \returns a \c MonoString. On failure returns NULL and sets \p error.
7179 mono_string_from_utf32_checked (mono_unichar4 *data, MonoError *error)
7181 MONO_REQ_GC_UNSAFE_MODE;
7184 MonoString* result = NULL;
7185 mono_unichar2 *utf16_output = NULL;
7186 GError *gerror = NULL;
7187 glong items_written;
7193 while (data [len]) len++;
7195 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &gerror);
7198 g_error_free (gerror);
7200 result = mono_string_from_utf16_checked (utf16_output, error);
7201 g_free (utf16_output);
7206 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
7208 MONO_REQ_GC_UNSAFE_MODE;
7215 r = mono_string_to_utf8_ignore (s);
7217 r = mono_string_to_utf8_checked (s, error);
7218 if (!mono_error_ok (error))
7225 len = strlen (r) + 1;
7227 mp_s = (char *)mono_mempool_alloc (mp, len);
7229 mp_s = (char *)mono_image_alloc (image, len);
7231 memcpy (mp_s, r, len);
7239 * mono_string_to_utf8_image:
7240 * \param s a \c System.String
7241 * Same as \c mono_string_to_utf8, but allocate the string from the image mempool.
7244 mono_string_to_utf8_image (MonoImage *image, MonoStringHandle s, MonoError *error)
7246 MONO_REQ_GC_UNSAFE_MODE;
7248 return mono_string_to_utf8_internal (NULL, image, MONO_HANDLE_RAW (s), FALSE, error); /* FIXME pin the string */
7252 * mono_string_to_utf8_mp:
7253 * \param s a \c System.String
7254 * Same as \c mono_string_to_utf8, but allocate the string from a mempool.
7257 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
7259 MONO_REQ_GC_UNSAFE_MODE;
7261 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
7265 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
7268 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
7270 eh_callbacks = *cbs;
7273 MonoRuntimeExceptionHandlingCallbacks *
7274 mono_get_eh_callbacks (void)
7276 return &eh_callbacks;
7280 * mono_raise_exception:
7281 * \param ex exception object
7282 * Signal the runtime that the exception \p ex has been raised in unmanaged code.
7285 mono_raise_exception (MonoException *ex)
7287 MONO_REQ_GC_UNSAFE_MODE;
7290 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
7291 * that will cause gcc to omit the function epilog, causing problems when
7292 * the JIT tries to walk the stack, since the return address on the stack
7293 * will point into the next function in the executable, not this one.
7295 eh_callbacks.mono_raise_exception (ex);
7299 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
7301 MONO_REQ_GC_UNSAFE_MODE;
7303 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
7307 * mono_wait_handle_new:
7308 * \param domain Domain where the object will be created
7309 * \param handle Handle for the wait handle
7310 * \param error set on error.
7311 * \returns A new \c MonoWaitHandle created in the given domain for the
7312 * given handle. On failure returns NULL and sets \p error.
7315 mono_wait_handle_new (MonoDomain *domain, HANDLE handle, MonoError *error)
7317 MONO_REQ_GC_UNSAFE_MODE;
7319 MonoWaitHandle *res;
7320 gpointer params [1];
7321 static MonoMethod *handle_set;
7324 res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, error);
7325 return_val_if_nok (error, NULL);
7327 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
7329 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
7331 params [0] = &handle;
7333 mono_runtime_invoke_checked (handle_set, res, params, error);
7338 mono_wait_handle_get_handle (MonoWaitHandle *handle)
7340 MONO_REQ_GC_UNSAFE_MODE;
7342 static MonoClassField *f_safe_handle = NULL;
7345 if (!f_safe_handle) {
7346 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safeWaitHandle");
7347 g_assert (f_safe_handle);
7350 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
7356 mono_runtime_capture_context (MonoDomain *domain, MonoError *error)
7358 MONO_REQ_GC_UNSAFE_MODE;
7360 RuntimeInvokeFunction runtime_invoke;
7364 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
7365 MonoMethod *method = mono_get_context_capture_method ();
7366 MonoMethod *wrapper;
7369 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
7370 domain->capture_context_runtime_invoke = mono_compile_method_checked (wrapper, error);
7371 return_val_if_nok (error, NULL);
7372 domain->capture_context_method = mono_compile_method_checked (method, error);
7373 return_val_if_nok (error, NULL);
7376 runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
7378 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
7381 * mono_async_result_new:
7382 * \param domain domain where the object will be created.
7383 * \param handle wait handle.
7384 * \param state state to pass to AsyncResult
7385 * \param data C closure data.
7386 * \param error set on error.
7387 * Creates a new MonoAsyncResult (\c AsyncResult C# class) in the given domain.
7388 * If the handle is not null, the handle is initialized to a \c MonoWaitHandle.
7389 * On failure returns NULL and sets \p error.
7392 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data, MonoError *error)
7394 MONO_REQ_GC_UNSAFE_MODE;
7397 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, error);
7398 return_val_if_nok (error, NULL);
7399 MonoObject *context = mono_runtime_capture_context (domain, error);
7400 return_val_if_nok (error, NULL);
7401 /* we must capture the execution context from the original thread */
7403 MONO_OBJECT_SETREF (res, execution_context, context);
7404 /* note: result may be null if the flow is suppressed */
7407 res->data = (void **)data;
7408 MONO_OBJECT_SETREF (res, object_data, object_data);
7409 MONO_OBJECT_SETREF (res, async_state, state);
7410 MonoWaitHandle *wait_handle = mono_wait_handle_new (domain, handle, error);
7411 return_val_if_nok (error, NULL);
7413 MONO_OBJECT_SETREF (res, handle, (MonoObject *) wait_handle);
7415 res->sync_completed = FALSE;
7416 res->completed = FALSE;
7422 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
7424 MONO_REQ_GC_UNSAFE_MODE;
7431 g_assert (ares->async_delegate);
7433 ac = (MonoAsyncCall*) ares->object_data;
7435 res = mono_runtime_delegate_invoke_checked (ares->async_delegate, (void**) &ares->async_state, &error);
7436 if (mono_error_set_pending_exception (&error))
7439 gpointer wait_event = NULL;
7441 ac->msg->exc = NULL;
7443 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args, &error);
7445 /* The exit side of the invoke must not be aborted as it would leave the runtime in an undefined state */
7446 mono_threads_begin_abort_protected_block ();
7448 if (!ac->msg->exc) {
7449 MonoException *ex = mono_error_convert_to_exception (&error);
7450 ac->msg->exc = (MonoObject *)ex;
7452 mono_error_cleanup (&error);
7455 MONO_OBJECT_SETREF (ac, res, res);
7457 mono_monitor_enter ((MonoObject*) ares);
7458 ares->completed = 1;
7460 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
7461 mono_monitor_exit ((MonoObject*) ares);
7463 if (wait_event != NULL)
7464 mono_w32event_set (wait_event);
7466 error_init (&error); //the else branch would leave it in an undefined state
7468 mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
7470 mono_threads_end_abort_protected_block ();
7472 if (mono_error_set_pending_exception (&error))
7480 mono_message_init (MonoDomain *domain,
7481 MonoMethodMessage *this_obj,
7482 MonoReflectionMethod *method,
7483 MonoArray *out_args,
7486 MONO_REQ_GC_UNSAFE_MODE;
7488 static MonoMethod *init_message_method = NULL;
7490 if (!init_message_method) {
7491 init_message_method = mono_class_get_method_from_name (mono_defaults.mono_method_message_class, "InitMessage", 2);
7492 g_assert (init_message_method != NULL);
7496 /* FIXME set domain instead? */
7497 g_assert (domain == mono_domain_get ());
7504 mono_runtime_invoke_checked (init_message_method, this_obj, args, error);
7505 return is_ok (error);
7508 #ifndef DISABLE_REMOTING
7510 * mono_remoting_invoke:
7511 * \param real_proxy pointer to a \c RealProxy object
7512 * \param msg The \c MonoMethodMessage to execute
7513 * \param exc used to store exceptions
7514 * \param out_args used to store output arguments
7515 * This is used to call \c RealProxy::Invoke(). \c RealProxy::Invoke() returns an
7516 * \c IMessage interface and it is not trivial to extract results from there. So
7517 * we call an helper method \c PrivateInvoke instead of calling
7518 * \c RealProxy::Invoke() directly.
7519 * \returns the result object.
7522 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, MonoObject **exc, MonoArray **out_args, MonoError *error)
7524 MONO_REQ_GC_UNSAFE_MODE;
7527 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
7534 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
7537 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
7539 mono_error_set_not_supported (error, "Linked away.");
7542 real_proxy->vtable->domain->private_invoke_method = im;
7545 pa [0] = real_proxy;
7550 o = mono_runtime_try_invoke (im, NULL, pa, exc, error);
7551 return_val_if_nok (error, NULL);
7558 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
7559 MonoObject **exc, MonoArray **out_args, MonoError *error)
7561 MONO_REQ_GC_UNSAFE_MODE;
7563 static MonoClass *object_array_klass;
7568 MonoMethodSignature *sig;
7570 int i, j, outarg_count = 0;
7572 #ifndef DISABLE_REMOTING
7573 if (target && mono_object_is_transparent_proxy (target)) {
7574 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
7575 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7576 target = tp->rp->unwrapped_server;
7578 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args, error);
7583 domain = mono_domain_get ();
7584 method = msg->method->method;
7585 sig = mono_method_signature (method);
7587 for (i = 0; i < sig->param_count; i++) {
7588 if (sig->params [i]->byref)
7592 if (!object_array_klass) {
7595 klass = mono_array_class_get (mono_defaults.object_class, 1);
7598 mono_memory_barrier ();
7599 object_array_klass = klass;
7602 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, error);
7603 return_val_if_nok (error, NULL);
7605 mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
7608 MonoObject *ret = mono_runtime_try_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc, error);
7609 return_val_if_nok (error, NULL);
7611 for (i = 0, j = 0; i < sig->param_count; i++) {
7612 if (sig->params [i]->byref) {
7614 arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
7615 mono_array_setref (*out_args, j, arg);
7624 * prepare_to_string_method:
7626 * @target: Set to @obj or unboxed value if a valuetype
7628 * Returns: the ToString override for @obj. If @obj is a valuetype, @target is unboxed otherwise it's @obj.
7631 prepare_to_string_method (MonoObject *obj, void **target)
7633 MONO_REQ_GC_UNSAFE_MODE;
7635 static MonoMethod *to_string = NULL;
7643 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
7645 method = mono_object_get_virtual_method (obj, to_string);
7647 // Unbox value type if needed
7648 if (mono_class_is_valuetype (mono_method_get_class (method))) {
7649 *target = mono_object_unbox (obj);
7655 * mono_object_to_string:
7656 * \param obj The object
7657 * \param exc Any exception thrown by \c ToString. May be NULL.
7658 * \returns the result of calling \c ToString on an object.
7661 mono_object_to_string (MonoObject *obj, MonoObject **exc)
7664 MonoString *s = NULL;
7666 MonoMethod *method = prepare_to_string_method (obj, &target);
7668 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
7669 if (*exc == NULL && !mono_error_ok (&error))
7670 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
7672 mono_error_cleanup (&error);
7674 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
7675 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
7682 * mono_object_to_string_checked:
7683 * \param obj The object
7684 * \param error Set on error.
7685 * \returns the result of calling \c ToString() on an object. If the
7686 * method cannot be invoked or if it raises an exception, sets \p error
7690 mono_object_to_string_checked (MonoObject *obj, MonoError *error)
7694 MonoMethod *method = prepare_to_string_method (obj, &target);
7695 return (MonoString*) mono_runtime_invoke_checked (method, target, NULL, error);
7699 * mono_object_try_to_string:
7700 * \param obj The object
7701 * \param exc Any exception thrown by \c ToString(). Must not be NULL.
7702 * \param error Set if method cannot be invoked.
7703 * \returns the result of calling \c ToString() on an object. If the
7704 * method cannot be invoked sets \p error, if it raises an exception sets \p exc,
7708 mono_object_try_to_string (MonoObject *obj, MonoObject **exc, MonoError *error)
7713 MonoMethod *method = prepare_to_string_method (obj, &target);
7714 return (MonoString*) mono_runtime_try_invoke (method, target, NULL, exc, error);
7720 get_native_backtrace (MonoException *exc_raw)
7722 HANDLE_FUNCTION_ENTER ();
7723 MONO_HANDLE_DCL(MonoException, exc);
7724 char * trace = mono_exception_handle_get_native_backtrace (exc);
7725 HANDLE_FUNCTION_RETURN_VAL (trace);
7729 * mono_print_unhandled_exception:
7730 * \param exc The exception
7731 * Prints the unhandled exception.
7734 mono_print_unhandled_exception (MonoObject *exc)
7736 MONO_REQ_GC_UNSAFE_MODE;
7739 char *message = (char*)"";
7740 gboolean free_message = FALSE;
7743 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
7744 message = g_strdup ("OutOfMemoryException");
7745 free_message = TRUE;
7746 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
7747 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
7748 free_message = TRUE;
7751 if (((MonoException*)exc)->native_trace_ips) {
7752 message = get_native_backtrace ((MonoException*)exc);
7753 free_message = TRUE;
7755 MonoObject *other_exc = NULL;
7756 str = mono_object_try_to_string (exc, &other_exc, &error);
7757 if (other_exc == NULL && !is_ok (&error))
7758 other_exc = (MonoObject*)mono_error_convert_to_exception (&error);
7760 mono_error_cleanup (&error);
7762 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
7763 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
7765 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
7766 original_backtrace, nested_backtrace);
7768 g_free (original_backtrace);
7769 g_free (nested_backtrace);
7770 free_message = TRUE;
7772 message = mono_string_to_utf8_checked (str, &error);
7773 if (!mono_error_ok (&error)) {
7774 mono_error_cleanup (&error);
7775 message = (char *) "";
7777 free_message = TRUE;
7784 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
7785 * exc->vtable->klass->name, message);
7787 g_printerr ("\nUnhandled Exception:\n%s\n", message);
7794 * mono_delegate_ctor_with_method:
7795 * \param this pointer to an uninitialized delegate object
7796 * \param target target object
7797 * \param addr pointer to native code
7798 * \param method method
7799 * \param error set on error.
7800 * Initialize a delegate and sets a specific method, not the one
7801 * associated with \p addr. This is useful when sharing generic code.
7802 * In that case \p addr will most probably not be associated with the
7803 * correct instantiation of the method.
7804 * On failure returns FALSE and sets \p error.
7807 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method, MonoError *error)
7809 MONO_REQ_GC_UNSAFE_MODE;
7812 MonoDelegate *delegate = (MonoDelegate *)this_obj;
7814 g_assert (this_obj);
7817 g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
7820 delegate->method = method;
7822 mono_stats.delegate_creations++;
7824 #ifndef DISABLE_REMOTING
7825 if (target && mono_object_is_transparent_proxy (target)) {
7827 method = mono_marshal_get_remoting_invoke (method);
7828 #ifdef ENABLE_INTERPRETER
7829 g_error ("need RuntimeMethod in method_ptr when using interpreter");
7831 delegate->method_ptr = mono_compile_method_checked (method, error);
7832 return_val_if_nok (error, FALSE);
7833 MONO_OBJECT_SETREF (delegate, target, target);
7837 delegate->method_ptr = addr;
7838 MONO_OBJECT_SETREF (delegate, target, target);
7841 delegate->invoke_impl = callbacks.create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
7842 if (callbacks.init_delegate)
7843 callbacks.init_delegate (delegate);
7848 * mono_delegate_ctor:
7849 * \param this pointer to an uninitialized delegate object
7850 * \param target target object
7851 * \param addr pointer to native code
7852 * \param error set on error.
7853 * This is used to initialize a delegate.
7854 * On failure returns FALSE and sets \p error.
7857 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoError *error)
7859 MONO_REQ_GC_UNSAFE_MODE;
7862 MonoDomain *domain = mono_domain_get ();
7864 MonoMethod *method = NULL;
7868 ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
7870 if (!ji && domain != mono_get_root_domain ())
7871 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
7873 method = mono_jit_info_get_method (ji);
7874 g_assert (!mono_class_is_gtd (method->klass));
7877 return mono_delegate_ctor_with_method (this_obj, target, addr, method, error);
7881 * mono_method_call_message_new:
7882 * \param method method to encapsulate
7883 * \param params parameters to the method
7884 * \param invoke optional, delegate invoke.
7885 * \param cb async callback delegate.
7886 * \param state state passed to the async callback.
7887 * \param error set on error.
7888 * Translates arguments pointers into a \c MonoMethodMessage.
7889 * On failure returns NULL and sets \p error.
7892 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
7893 MonoDelegate **cb, MonoObject **state, MonoError *error)
7895 MONO_REQ_GC_UNSAFE_MODE;
7899 MonoDomain *domain = mono_domain_get ();
7900 MonoMethodSignature *sig = mono_method_signature (method);
7901 MonoMethodMessage *msg;
7904 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
7905 return_val_if_nok (error, NULL);
7908 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, error);
7909 return_val_if_nok (error, NULL);
7910 mono_message_init (domain, msg, rm, NULL, error);
7911 return_val_if_nok (error, NULL);
7912 count = sig->param_count - 2;
7914 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
7915 return_val_if_nok (error, NULL);
7916 mono_message_init (domain, msg, rm, NULL, error);
7917 return_val_if_nok (error, NULL);
7918 count = sig->param_count;
7921 for (i = 0; i < count; i++) {
7926 if (sig->params [i]->byref)
7927 vpos = *((gpointer *)params [i]);
7931 klass = mono_class_from_mono_type (sig->params [i]);
7933 if (klass->valuetype) {
7934 arg = mono_value_box_checked (domain, klass, vpos, error);
7935 return_val_if_nok (error, NULL);
7937 arg = *((MonoObject **)vpos);
7939 mono_array_setref (msg->args, i, arg);
7942 if (cb != NULL && state != NULL) {
7943 *cb = *((MonoDelegate **)params [i]);
7945 *state = *((MonoObject **)params [i]);
7952 * mono_method_return_message_restore:
7954 * Restore results from message based processing back to arguments pointers
7957 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args, MonoError *error)
7959 MONO_REQ_GC_UNSAFE_MODE;
7963 MonoMethodSignature *sig = mono_method_signature (method);
7964 int i, j, type, size, out_len;
7966 if (out_args == NULL)
7968 out_len = mono_array_length (out_args);
7972 for (i = 0, j = 0; i < sig->param_count; i++) {
7973 MonoType *pt = sig->params [i];
7978 mono_error_set_execution_engine (error, "The proxy call returned an incorrect number of output arguments");
7982 arg = (char *)mono_array_get (out_args, gpointer, j);
7985 g_assert (type != MONO_TYPE_VOID);
7987 if (MONO_TYPE_IS_REFERENCE (pt)) {
7988 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
7991 MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
7992 size = mono_class_value_size (klass, NULL);
7993 if (klass->has_references)
7994 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
7996 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
7998 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
7999 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
8008 #ifndef DISABLE_REMOTING
8011 * mono_load_remote_field:
8012 * \param this pointer to an object
8013 * \param klass klass of the object containing \p field
8014 * \param field the field to load
8015 * \param res a storage to store the result
8016 * This method is called by the runtime on attempts to load fields of
8017 * transparent proxy objects. \p this points to such TP, \p klass is the class of
8018 * the object containing \p field. \p res is a storage location which can be
8019 * used to store the result.
8020 * \returns an address pointing to the value of field.
8023 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
8026 gpointer result = mono_load_remote_field_checked (this_obj, klass, field, res, &error);
8027 mono_error_cleanup (&error);
8032 * mono_load_remote_field_checked:
8033 * \param this pointer to an object
8034 * \param klass klass of the object containing \p field
8035 * \param field the field to load
8036 * \param res a storage to store the result
8037 * \param error set on error
8038 * This method is called by the runtime on attempts to load fields of
8039 * transparent proxy objects. \p this points to such TP, \p klass is the class of
8040 * the object containing \p field. \p res is a storage location which can be
8041 * used to store the result.
8042 * \returns an address pointing to the value of field. On failure returns NULL and sets \p error.
8045 mono_load_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res, MonoError *error)
8047 MONO_REQ_GC_UNSAFE_MODE;
8049 static MonoMethod *getter = NULL;
8053 MonoDomain *domain = mono_domain_get ();
8054 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8055 MonoClass *field_class;
8056 MonoMethodMessage *msg;
8057 MonoArray *out_args;
8061 g_assert (mono_object_is_transparent_proxy (this_obj));
8062 g_assert (res != NULL);
8064 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8065 mono_field_get_value (tp->rp->unwrapped_server, field, res);
8070 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
8072 mono_error_set_not_supported (error, "Linked away.");
8077 field_class = mono_class_from_mono_type (field->type);
8079 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8080 return_val_if_nok (error, NULL);
8081 out_args = mono_array_new_checked (domain, mono_defaults.object_class, 1, error);
8082 return_val_if_nok (error, NULL);
8083 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, error);
8084 return_val_if_nok (error, NULL);
8085 mono_message_init (domain, msg, rm, out_args, error);
8086 return_val_if_nok (error, NULL);
8088 full_name = mono_type_get_full_name (klass);
8089 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
8090 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
8093 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8094 return_val_if_nok (error, NULL);
8097 mono_error_set_exception_instance (error, (MonoException *)exc);
8101 if (mono_array_length (out_args) == 0)
8104 mono_gc_wbarrier_generic_store (res, mono_array_get (out_args, MonoObject *, 0));
8106 if (field_class->valuetype) {
8107 return ((char *)*res) + sizeof (MonoObject);
8113 * mono_load_remote_field_new:
8117 * Missing documentation.
8120 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
8124 MonoObject *result = mono_load_remote_field_new_checked (this_obj, klass, field, &error);
8125 mono_error_cleanup (&error);
8130 * mono_load_remote_field_new_checked:
8131 * \param this pointer to an object
8132 * \param klass klass of the object containing \p field
8133 * \param field the field to load
8134 * \param error set on error.
8135 * This method is called by the runtime on attempts to load fields of
8136 * transparent proxy objects. \p this points to such TP, \p klass is the class of
8137 * the object containing \p field.
8138 * \returns a freshly allocated object containing the value of the field. On failure returns NULL and sets \p error.
8141 mono_load_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoError *error)
8143 MONO_REQ_GC_UNSAFE_MODE;
8147 static MonoMethod *tp_load = NULL;
8149 g_assert (mono_object_is_transparent_proxy (this_obj));
8152 tp_load = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "LoadRemoteFieldNew", -1);
8154 mono_error_set_not_supported (error, "Linked away.");
8159 /* MonoType *type = mono_class_get_type (klass); */
8165 return mono_runtime_invoke_checked (tp_load, this_obj, args, error);
8169 * mono_store_remote_field:
8170 * \param this_obj pointer to an object
8171 * \param klass klass of the object containing \p field
8172 * \param field the field to load
8173 * \param val the value/object to store
8174 * This method is called by the runtime on attempts to store fields of
8175 * transparent proxy objects. \p this_obj points to such TP, \p klass is the class of
8176 * the object containing \p field. \p val is the new value to store in \p field.
8179 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
8182 (void) mono_store_remote_field_checked (this_obj, klass, field, val, &error);
8183 mono_error_cleanup (&error);
8187 * mono_store_remote_field_checked:
8188 * \param this_obj pointer to an object
8189 * \param klass klass of the object containing \p field
8190 * \param field the field to load
8191 * \param val the value/object to store
8192 * \param error set on error
8193 * This method is called by the runtime on attempts to store fields of
8194 * transparent proxy objects. \p this_obj points to such TP, \p klass is the class of
8195 * the object containing \p field. \p val is the new value to store in \p field.
8196 * \returns on success returns TRUE, on failure returns FALSE and sets \p error.
8199 mono_store_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val, MonoError *error)
8202 MONO_REQ_GC_UNSAFE_MODE;
8206 MonoDomain *domain = mono_domain_get ();
8207 MonoClass *field_class;
8210 g_assert (mono_object_is_transparent_proxy (this_obj));
8212 field_class = mono_class_from_mono_type (field->type);
8214 if (field_class->valuetype) {
8215 arg = mono_value_box_checked (domain, field_class, val, error);
8216 return_val_if_nok (error, FALSE);
8218 arg = *((MonoObject**)val);
8221 return mono_store_remote_field_new_checked (this_obj, klass, field, arg, error);
8225 * mono_store_remote_field_new:
8230 * Missing documentation
8233 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
8236 (void) mono_store_remote_field_new_checked (this_obj, klass, field, arg, &error);
8237 mono_error_cleanup (&error);
8241 * mono_store_remote_field_new_checked:
8247 * Missing documentation
8250 mono_store_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg, MonoError *error)
8252 MONO_REQ_GC_UNSAFE_MODE;
8254 static MonoMethod *tp_store = NULL;
8258 g_assert (mono_object_is_transparent_proxy (this_obj));
8261 tp_store = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "StoreRemoteField", -1);
8263 mono_error_set_not_supported (error, "Linked away.");
8273 mono_runtime_invoke_checked (tp_store, this_obj, args, error);
8274 return is_ok (error);
8279 * mono_create_ftnptr:
8281 * Given a function address, create a function descriptor for it.
8282 * This is only needed on some platforms.
8285 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
8287 return callbacks.create_ftnptr (domain, addr);
8291 * mono_get_addr_from_ftnptr:
8293 * Given a pointer to a function descriptor, return the function address.
8294 * This is only needed on some platforms.
8297 mono_get_addr_from_ftnptr (gpointer descr)
8299 return callbacks.get_addr_from_ftnptr (descr);
8303 * mono_string_chars:
8304 * \param s a \c MonoString
8305 * \returns a pointer to the UTF-16 characters stored in the \c MonoString
8308 mono_string_chars (MonoString *s)
8310 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
8316 * mono_string_length:
8317 * \param s MonoString
8318 * \returns the length in characters of the string
8321 mono_string_length (MonoString *s)
8323 MONO_REQ_GC_UNSAFE_MODE;
8329 * mono_string_handle_length:
8330 * \param s \c MonoString
8331 * \returns the length in characters of the string
8334 mono_string_handle_length (MonoStringHandle s)
8336 MONO_REQ_GC_UNSAFE_MODE;
8338 return MONO_HANDLE_GETVAL (s, length);
8343 * mono_array_length:
8344 * \param array a \c MonoArray*
8345 * \returns the total number of elements in the array. This works for
8346 * both vectors and multidimensional arrays.
8349 mono_array_length (MonoArray *array)
8351 MONO_REQ_GC_UNSAFE_MODE;
8353 return array->max_length;
8357 * mono_array_addr_with_size:
8358 * \param array a \c MonoArray*
8359 * \param size size of the array elements
8360 * \param idx index into the array
8361 * Use this function to obtain the address for the \p idx item on the
8362 * \p array containing elements of size \p size.
8364 * This method performs no bounds checking or type checking.
8365 * \returns the address of the \p idx element in the array.
8368 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
8370 MONO_REQ_GC_UNSAFE_MODE;
8372 return ((char*)(array)->vector) + size * idx;
8377 mono_glist_to_array (GList *list, MonoClass *eclass, MonoError *error)
8379 MonoDomain *domain = mono_domain_get ();
8387 len = g_list_length (list);
8388 res = mono_array_new_checked (domain, eclass, len, error);
8389 return_val_if_nok (error, NULL);
8391 for (i = 0; list; list = list->next, i++)
8392 mono_array_set (res, gpointer, i, list->data);
8399 * The following section is purely to declare prototypes and
8400 * document the API, as these C files are processed by our
8406 * \param array array to alter
8407 * \param element_type A C type name, this macro will use the sizeof(type) to determine the element size
8408 * \param index index into the array
8409 * \param value value to set
8410 * Value Type version: This sets the \p index's element of the \p array
8411 * with elements of size sizeof(type) to the provided \p value.
8413 * This macro does not attempt to perform type checking or bounds checking.
8415 * Use this to set value types in a \c MonoArray.
8417 void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
8422 * mono_array_setref:
8423 * \param array array to alter
8424 * \param index index into the array
8425 * \param value value to set
8426 * Reference Type version. This sets the \p index's element of the
8427 * \p array with elements of size sizeof(type) to the provided \p value.
8429 * This macro does not attempt to perform type checking or bounds checking.
8431 * Use this to reference types in a \c MonoArray.
8433 void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
8439 * \param array array on which to operate on
8440 * \param element_type C element type (example: \c MonoString*, \c int, \c MonoObject*)
8441 * \param index index into the array
8443 * Use this macro to retrieve the \p index element of an \p array and
8444 * extract the value assuming that the elements of the array match
8445 * the provided type value.
8447 * This method can be used with both arrays holding value types and
8448 * reference types. For reference types, the \p type parameter should
8449 * be a \c MonoObject* or any subclass of it, like \c MonoString*.
8451 * This macro does not attempt to perform type checking or bounds checking.
8453 * \returns The element at the \p index position in the \p array.
8455 Type mono_array_get (MonoArray *array, Type element_type, uintptr_t index)