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 mono_domain_add_class_static_data (domain, klass, vt->vtable [klass->vtable_size], NULL);
1972 if (bitmap != default_bitmap)
1975 vt->vtable [klass->vtable_size] = mono_domain_alloc0 (domain, class_size);
1977 vt->has_static_fields = TRUE;
1978 mono_stats.class_static_data_size += class_size;
1982 while ((field = mono_class_get_fields (klass, &iter))) {
1983 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1985 if (mono_field_is_deleted (field))
1987 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1988 gint32 special_static = klass->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (klass, field);
1989 if (special_static != SPECIAL_STATIC_NONE) {
1990 guint32 size, offset;
1992 gsize default_bitmap [4] = {0};
1997 if (mono_type_is_reference (field->type)) {
1998 default_bitmap [0] = 1;
2000 bitmap = default_bitmap;
2001 } else if (mono_type_is_struct (field->type)) {
2002 fclass = mono_class_from_mono_type (field->type);
2003 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
2004 numbits = max_set + 1;
2006 default_bitmap [0] = 0;
2008 bitmap = default_bitmap;
2010 size = mono_type_size (field->type, &align);
2011 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
2012 if (!domain->special_static_fields)
2013 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2014 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2015 if (bitmap != default_bitmap)
2018 * This marks the field as special static to speed up the
2019 * checks in mono_field_static_get/set_value ().
2025 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2026 MonoClass *fklass = mono_class_from_mono_type (field->type);
2027 const char *data = mono_field_get_data (field);
2029 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2030 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2031 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2034 if (fklass->valuetype) {
2035 memcpy (t, data, mono_class_value_size (fklass, NULL));
2037 /* it's a pointer type: add check */
2038 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2045 vt->max_interface_id = klass->max_interface_id;
2046 vt->interface_bitmap = klass->interface_bitmap;
2048 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2049 // class->name, klass->interface_offsets_count);
2051 /* Initialize vtable */
2052 if (callbacks.get_vtable_trampoline) {
2053 // This also covers the AOT case
2054 for (i = 0; i < klass->vtable_size; ++i) {
2055 vt->vtable [i] = callbacks.get_vtable_trampoline (vt, i);
2058 mono_class_setup_vtable (klass);
2060 for (i = 0; i < klass->vtable_size; ++i) {
2063 cm = klass->vtable [i];
2065 vt->vtable [i] = callbacks.create_jit_trampoline (domain, cm, error);
2066 if (!is_ok (error)) {
2067 mono_domain_unlock (domain);
2068 mono_loader_unlock ();
2075 if (imt_table_bytes) {
2076 /* Now that the vtable is full, we can actually fill up the IMT */
2077 for (i = 0; i < MONO_IMT_SIZE; ++i)
2078 interface_offsets [i] = callbacks.get_imt_trampoline (vt, i);
2082 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2083 * re-acquire them and check if another thread has created the vtable in the meantime.
2085 /* Special case System.MonoType to avoid infinite recursion */
2086 if (klass != mono_defaults.runtimetype_class) {
2087 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2088 if (!is_ok (error)) {
2089 mono_domain_unlock (domain);
2090 mono_loader_unlock ();
2094 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2095 /* This is unregistered in
2096 unregister_vtable_reflection_type() in
2098 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2101 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (klass));
2103 /* class_vtable_array keeps an array of created vtables
2105 g_ptr_array_add (domain->class_vtable_array, vt);
2106 /* klass->runtime_info is protected by the loader lock, both when
2107 * it it enlarged and when it is stored info.
2111 * Store the vtable in klass->runtime_info.
2112 * klass->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2114 mono_memory_barrier ();
2116 old_info = klass->runtime_info;
2117 if (old_info && old_info->max_domain >= domain->domain_id) {
2118 /* someone already created a large enough runtime info */
2119 old_info->domain_vtables [domain->domain_id] = vt;
2121 int new_size = domain->domain_id;
2123 new_size = MAX (new_size, old_info->max_domain);
2125 /* make the new size a power of two */
2127 while (new_size > i)
2130 /* this is a bounded memory retention issue: may want to
2131 * handle it differently when we'll have a rcu-like system.
2133 runtime_info = (MonoClassRuntimeInfo *)mono_image_alloc0 (klass->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2134 runtime_info->max_domain = new_size - 1;
2135 /* copy the stuff from the older info */
2137 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2139 runtime_info->domain_vtables [domain->domain_id] = vt;
2141 mono_memory_barrier ();
2142 klass->runtime_info = runtime_info;
2145 if (klass == mono_defaults.runtimetype_class) {
2146 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2147 if (!is_ok (error)) {
2148 mono_domain_unlock (domain);
2149 mono_loader_unlock ();
2153 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2154 /* This is unregistered in
2155 unregister_vtable_reflection_type() in
2157 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2160 mono_domain_unlock (domain);
2161 mono_loader_unlock ();
2163 /* make sure the parent is initialized */
2164 /*FIXME shouldn't this fail the current type?*/
2166 mono_class_vtable_full (domain, klass->parent, error);
2171 #ifndef DISABLE_REMOTING
2173 * mono_class_proxy_vtable:
2174 * \param domain the application domain
2175 * \param remove_class the remote class
2176 * \param error set on error
2177 * Creates a vtable for transparent proxies. It is basically
2178 * a copy of the real vtable of the class wrapped in \p remote_class,
2179 * but all function pointers invoke the remoting functions, and
2180 * \c vtable->klass points to the transparent proxy class, and not to \p class.
2182 * On failure returns NULL and sets \p error
2185 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type, MonoError *error)
2187 MONO_REQ_GC_UNSAFE_MODE;
2189 MonoVTable *vt, *pvt;
2190 int i, j, vtsize, extra_interface_vtsize = 0;
2191 guint32 max_interface_id;
2193 GSList *extra_interfaces = NULL;
2194 MonoClass *klass = remote_class->proxy_class;
2195 gpointer *interface_offsets;
2196 uint8_t *bitmap = NULL;
2198 size_t imt_table_bytes;
2200 #ifdef COMPRESSED_INTERFACE_BITMAP
2206 vt = mono_class_vtable (domain, klass);
2207 g_assert (vt); /*FIXME property handle failure*/
2208 max_interface_id = vt->max_interface_id;
2210 /* Calculate vtable space for extra interfaces */
2211 for (j = 0; j < remote_class->interface_count; j++) {
2212 MonoClass* iclass = remote_class->interfaces[j];
2216 /*FIXME test for interfaces with variant generic arguments*/
2217 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, iclass->interface_id))
2218 continue; /* interface implemented by the class */
2219 if (g_slist_find (extra_interfaces, iclass))
2222 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2224 method_count = mono_class_num_methods (iclass);
2226 ifaces = mono_class_get_implemented_interfaces (iclass, error);
2230 for (i = 0; i < ifaces->len; ++i) {
2231 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2232 /*FIXME test for interfaces with variant generic arguments*/
2233 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, ic->interface_id))
2234 continue; /* interface implemented by the class */
2235 if (g_slist_find (extra_interfaces, ic))
2237 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2238 method_count += mono_class_num_methods (ic);
2240 g_ptr_array_free (ifaces, TRUE);
2244 extra_interface_vtsize += method_count * sizeof (gpointer);
2245 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2248 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2249 mono_stats.imt_number_of_tables++;
2250 mono_stats.imt_tables_size += imt_table_bytes;
2252 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer);
2254 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2256 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2257 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2258 g_assert (!((gsize)pvt & 7));
2260 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer));
2262 pvt->klass = mono_defaults.transparent_proxy_class;
2263 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2264 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2266 /* initialize vtable */
2267 mono_class_setup_vtable (klass);
2268 for (i = 0; i < klass->vtable_size; ++i) {
2271 if ((cm = klass->vtable [i])) {
2272 pvt->vtable [i] = create_remoting_trampoline (domain, cm, target_type, error);
2276 pvt->vtable [i] = NULL;
2279 if (mono_class_is_abstract (klass)) {
2280 /* create trampolines for abstract methods */
2281 for (k = klass; k; k = k->parent) {
2283 gpointer iter = NULL;
2284 while ((m = mono_class_get_methods (k, &iter)))
2285 if (!pvt->vtable [m->slot]) {
2286 pvt->vtable [m->slot] = create_remoting_trampoline (domain, m, target_type, error);
2293 pvt->max_interface_id = max_interface_id;
2294 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2295 #ifdef COMPRESSED_INTERFACE_BITMAP
2296 bitmap = (uint8_t *)g_malloc0 (bsize);
2298 bitmap = (uint8_t *)mono_domain_alloc0 (domain, bsize);
2301 for (i = 0; i < klass->interface_offsets_count; ++i) {
2302 int interface_id = klass->interfaces_packed [i]->interface_id;
2303 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2306 if (extra_interfaces) {
2307 int slot = klass->vtable_size;
2313 /* Create trampolines for the methods of the interfaces */
2314 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2315 interf = (MonoClass *)list_item->data;
2317 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2321 while ((cm = mono_class_get_methods (interf, &iter))) {
2322 pvt->vtable [slot + j++] = create_remoting_trampoline (domain, cm, target_type, error);
2327 slot += mono_class_num_methods (interf);
2331 /* Now that the vtable is full, we can actually fill up the IMT */
2332 build_imt (klass, pvt, domain, interface_offsets, extra_interfaces);
2333 if (extra_interfaces) {
2334 g_slist_free (extra_interfaces);
2337 #ifdef COMPRESSED_INTERFACE_BITMAP
2338 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2339 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2340 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2343 pvt->interface_bitmap = bitmap;
2347 if (extra_interfaces)
2348 g_slist_free (extra_interfaces);
2349 #ifdef COMPRESSED_INTERFACE_BITMAP
2355 #endif /* DISABLE_REMOTING */
2358 * mono_class_field_is_special_static:
2359 * \returns whether \p field is a thread/context static field.
2362 mono_class_field_is_special_static (MonoClassField *field)
2364 MONO_REQ_GC_NEUTRAL_MODE
2366 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2368 if (mono_field_is_deleted (field))
2370 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2371 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2378 * mono_class_field_get_special_static_type:
2379 * \param field The \c MonoClassField describing the field.
2380 * \returns \c SPECIAL_STATIC_THREAD if the field is thread static, \c SPECIAL_STATIC_CONTEXT if it is context static,
2381 * \c SPECIAL_STATIC_NONE otherwise.
2384 mono_class_field_get_special_static_type (MonoClassField *field)
2386 MONO_REQ_GC_NEUTRAL_MODE
2388 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2389 return SPECIAL_STATIC_NONE;
2390 if (mono_field_is_deleted (field))
2391 return SPECIAL_STATIC_NONE;
2392 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2393 return field_is_special_static (field->parent, field);
2394 return SPECIAL_STATIC_NONE;
2398 * mono_class_has_special_static_fields:
2399 * \returns whether \p klass has any thread/context static fields.
2402 mono_class_has_special_static_fields (MonoClass *klass)
2404 MONO_REQ_GC_NEUTRAL_MODE
2406 MonoClassField *field;
2410 while ((field = mono_class_get_fields (klass, &iter))) {
2411 g_assert (field->parent == klass);
2412 if (mono_class_field_is_special_static (field))
2419 #ifndef DISABLE_REMOTING
2421 * create_remote_class_key:
2422 * Creates an array of pointers that can be used as a hash key for a remote class.
2423 * The first element of the array is the number of pointers.
2426 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2428 MONO_REQ_GC_NEUTRAL_MODE;
2433 if (remote_class == NULL) {
2434 if (mono_class_is_interface (extra_class)) {
2435 key = (void **)g_malloc (sizeof(gpointer) * 3);
2436 key [0] = GINT_TO_POINTER (2);
2437 key [1] = mono_defaults.marshalbyrefobject_class;
2438 key [2] = extra_class;
2440 key = (void **)g_malloc (sizeof(gpointer) * 2);
2441 key [0] = GINT_TO_POINTER (1);
2442 key [1] = extra_class;
2445 if (extra_class != NULL && mono_class_is_interface (extra_class)) {
2446 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2447 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2448 key [1] = remote_class->proxy_class;
2450 // Keep the list of interfaces sorted
2451 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2452 if (extra_class && remote_class->interfaces [i] > extra_class) {
2453 key [j++] = extra_class;
2456 key [j] = remote_class->interfaces [i];
2459 key [j] = extra_class;
2461 // Replace the old class. The interface list is the same
2462 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2463 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2464 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2465 for (i = 0; i < remote_class->interface_count; i++)
2466 key [2 + i] = remote_class->interfaces [i];
2474 * copy_remote_class_key:
2476 * Make a copy of KEY in the domain and return the copy.
2479 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2481 MONO_REQ_GC_NEUTRAL_MODE
2483 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2484 gpointer *mp_key = (gpointer *)mono_domain_alloc (domain, key_size);
2486 memcpy (mp_key, key, key_size);
2492 * mono_remote_class:
2493 * \param domain the application domain
2494 * \param class_name name of the remote class
2495 * \param error set on error
2496 * Creates and initializes a \c MonoRemoteClass object for a remote type.
2497 * On failure returns NULL and sets \p error
2500 mono_remote_class (MonoDomain *domain, MonoStringHandle class_name, MonoClass *proxy_class, MonoError *error)
2502 MONO_REQ_GC_UNSAFE_MODE;
2504 MonoRemoteClass *rc;
2505 gpointer* key, *mp_key;
2510 key = create_remote_class_key (NULL, proxy_class);
2512 mono_domain_lock (domain);
2513 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2517 mono_domain_unlock (domain);
2521 name = mono_string_to_utf8_mp (domain->mp, MONO_HANDLE_RAW (class_name), error);
2522 if (!is_ok (error)) {
2524 mono_domain_unlock (domain);
2528 mp_key = copy_remote_class_key (domain, key);
2532 if (mono_class_is_interface (proxy_class)) {
2533 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2534 rc->interface_count = 1;
2535 rc->interfaces [0] = proxy_class;
2536 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2538 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2539 rc->interface_count = 0;
2540 rc->proxy_class = proxy_class;
2543 rc->default_vtable = NULL;
2544 rc->xdomain_vtable = NULL;
2545 rc->proxy_class_name = name;
2546 #ifndef DISABLE_PERFCOUNTERS
2547 mono_perfcounters->loader_bytes += mono_string_length (MONO_HANDLE_RAW (class_name)) + 1;
2550 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2552 mono_domain_unlock (domain);
2557 * clone_remote_class:
2558 * Creates a copy of the remote_class, adding the provided class or interface
2560 static MonoRemoteClass*
2561 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2563 MONO_REQ_GC_NEUTRAL_MODE;
2565 MonoRemoteClass *rc;
2566 gpointer* key, *mp_key;
2568 key = create_remote_class_key (remote_class, extra_class);
2569 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2575 mp_key = copy_remote_class_key (domain, key);
2579 if (mono_class_is_interface (extra_class)) {
2581 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2582 rc->proxy_class = remote_class->proxy_class;
2583 rc->interface_count = remote_class->interface_count + 1;
2585 // Keep the list of interfaces sorted, since the hash key of
2586 // the remote class depends on this
2587 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2588 if (remote_class->interfaces [i] > extra_class && i == j)
2589 rc->interfaces [j++] = extra_class;
2590 rc->interfaces [j] = remote_class->interfaces [i];
2593 rc->interfaces [j] = extra_class;
2595 // Replace the old class. The interface array is the same
2596 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2597 rc->proxy_class = extra_class;
2598 rc->interface_count = remote_class->interface_count;
2599 if (rc->interface_count > 0)
2600 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2603 rc->default_vtable = NULL;
2604 rc->xdomain_vtable = NULL;
2605 rc->proxy_class_name = remote_class->proxy_class_name;
2607 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2613 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxyHandle rp, MonoError *error)
2615 MONO_REQ_GC_UNSAFE_MODE;
2619 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2620 mono_domain_lock (domain);
2621 gint32 target_domain_id = MONO_HANDLE_GETVAL (rp, target_domain_id);
2622 if (target_domain_id != -1) {
2623 if (remote_class->xdomain_vtable == NULL)
2624 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN, error);
2625 mono_domain_unlock (domain);
2626 mono_loader_unlock ();
2627 return_val_if_nok (error, NULL);
2628 return remote_class->xdomain_vtable;
2630 if (remote_class->default_vtable == NULL) {
2631 MonoReflectionTypeHandle reftype = MONO_HANDLE_NEW (MonoReflectionType, NULL);
2632 MONO_HANDLE_GET (reftype, rp, class_to_proxy);
2634 MonoType *type = MONO_HANDLE_GETVAL (reftype, type);
2635 MonoClass *klass = mono_class_from_mono_type (type);
2637 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)))
2638 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP, error);
2641 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN, error);
2642 /* N.B. both branches of the if modify error */
2643 if (!is_ok (error)) {
2644 mono_domain_unlock (domain);
2645 mono_loader_unlock ();
2650 mono_domain_unlock (domain);
2651 mono_loader_unlock ();
2652 return remote_class->default_vtable;
2656 * mono_upgrade_remote_class:
2657 * \param domain the application domain
2658 * \param tproxy the proxy whose remote class has to be upgraded.
2659 * \param klass class to which the remote class can be casted.
2660 * \param error set on error
2661 * Updates the vtable of the remote class by adding the necessary method slots
2662 * and interface offsets so it can be safely casted to klass. klass can be a
2663 * class or an interface. On success returns TRUE, on failure returns FALSE and sets \p error.
2666 mono_upgrade_remote_class (MonoDomain *domain, MonoObjectHandle proxy_object, MonoClass *klass, MonoError *error)
2668 MONO_REQ_GC_UNSAFE_MODE;
2672 MonoTransparentProxyHandle tproxy = MONO_HANDLE_CAST (MonoTransparentProxy, proxy_object);
2673 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (tproxy, remote_class);
2675 gboolean redo_vtable;
2676 if (mono_class_is_interface (klass)) {
2679 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2680 if (remote_class->interfaces [i] == klass)
2681 redo_vtable = FALSE;
2684 redo_vtable = (remote_class->proxy_class != klass);
2687 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2688 mono_domain_lock (domain);
2690 MonoRemoteClass *fresh_remote_class = clone_remote_class (domain, remote_class, klass);
2691 MONO_HANDLE_SETVAL (tproxy, remote_class, MonoRemoteClass*, fresh_remote_class);
2692 MonoRealProxyHandle real_proxy = MONO_HANDLE_NEW (MonoRealProxy, NULL);
2693 MONO_HANDLE_GET (real_proxy, tproxy, rp);
2694 MONO_HANDLE_SETVAL (proxy_object, vtable, MonoVTable*, mono_remote_class_vtable (domain, fresh_remote_class, real_proxy, error));
2700 mono_domain_unlock (domain);
2701 mono_loader_unlock ();
2702 return is_ok (error);
2704 #endif /* DISABLE_REMOTING */
2708 * mono_object_get_virtual_method:
2709 * \param obj object to operate on.
2710 * \param method method
2711 * Retrieves the \c MonoMethod that would be called on \p obj if \p obj is passed as
2712 * the instance of a callvirt of \p method.
2715 mono_object_get_virtual_method (MonoObject *obj_raw, MonoMethod *method)
2717 MONO_REQ_GC_UNSAFE_MODE;
2718 HANDLE_FUNCTION_ENTER ();
2720 MONO_HANDLE_DCL (MonoObject, obj);
2721 MonoMethod *result = mono_object_handle_get_virtual_method (obj, method, &error);
2722 mono_error_assert_ok (&error);
2723 HANDLE_FUNCTION_RETURN_VAL (result);
2727 * mono_object_handle_get_virtual_method:
2728 * \param obj object to operate on.
2729 * \param method method
2730 * Retrieves the \c MonoMethod that would be called on \p obj if \p obj is passed as
2731 * the instance of a callvirt of \p method.
2734 mono_object_handle_get_virtual_method (MonoObjectHandle obj, MonoMethod *method, MonoError *error)
2738 gboolean is_proxy = FALSE;
2739 MonoClass *klass = mono_handle_class (obj);
2740 if (mono_class_is_transparent_proxy (klass)) {
2741 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), remote_class);
2742 klass = remote_class->proxy_class;
2745 return class_get_virtual_method (klass, method, is_proxy, error);
2749 class_get_virtual_method (MonoClass *klass, MonoMethod *method, gboolean is_proxy, MonoError *error)
2754 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2757 mono_class_setup_vtable (klass);
2758 MonoMethod **vtable = klass->vtable;
2760 if (method->slot == -1) {
2761 /* method->slot might not be set for instances of generic methods */
2762 if (method->is_inflated) {
2763 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2764 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2767 g_assert_not_reached ();
2771 MonoMethod *res = NULL;
2772 /* check method->slot is a valid index: perform isinstance? */
2773 if (method->slot != -1) {
2774 if (mono_class_is_interface (method->klass)) {
2776 gboolean variance_used = FALSE;
2777 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2778 g_assert (iface_offset > 0);
2779 res = vtable [iface_offset + method->slot];
2782 res = vtable [method->slot];
2786 #ifndef DISABLE_REMOTING
2788 /* It may be an interface, abstract class method or generic method */
2789 if (!res || mono_method_signature (res)->generic_param_count)
2792 /* generic methods demand invoke_with_check */
2793 if (mono_method_signature (res)->generic_param_count)
2794 res = mono_marshal_get_remoting_invoke_with_check (res);
2797 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2798 res = mono_cominterop_get_invoke (res);
2801 res = mono_marshal_get_remoting_invoke (res);
2806 if (method->is_inflated) {
2807 /* Have to inflate the result */
2808 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, error);
2816 do_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2818 MONO_REQ_GC_UNSAFE_MODE;
2820 MonoObject *result = NULL;
2822 g_assert (callbacks.runtime_invoke);
2826 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2827 mono_profiler_method_start_invoke (method);
2829 result = callbacks.runtime_invoke (method, obj, params, exc, error);
2831 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2832 mono_profiler_method_end_invoke (method);
2834 if (!mono_error_ok (error))
2841 * mono_runtime_invoke:
2842 * \param method method to invoke
2843 * \param obj object instance
2844 * \param params arguments to the method
2845 * \param exc exception information.
2846 * Invokes the method represented by \p method on the object \p obj.
2847 * \p obj is the \c this pointer, it should be NULL for static
2848 * methods, a \c MonoObject* for object instances and a pointer to
2849 * the value type for value types.
2851 * The params array contains the arguments to the method with the
2852 * same convention: \c MonoObject* pointers for object instances and
2853 * pointers to the value type otherwise.
2855 * From unmanaged code you'll usually use the
2856 * \c mono_runtime_invoke variant.
2858 * Note that this function doesn't handle virtual methods for
2859 * you, it will exec the exact method you pass: we still need to
2860 * expose a function to lookup the derived class implementation
2861 * of a virtual method (there are examples of this in the code,
2864 * You can pass NULL as the \p exc argument if you don't want to
2865 * catch exceptions, otherwise, \c *exc will be set to the exception
2866 * thrown, if any. if an exception is thrown, you can't use the
2867 * \c MonoObject* result from the function.
2869 * If the method returns a value type, it is boxed in an object
2873 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2878 res = mono_runtime_try_invoke (method, obj, params, exc, &error);
2879 if (*exc == NULL && !mono_error_ok(&error)) {
2880 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
2882 mono_error_cleanup (&error);
2884 res = mono_runtime_invoke_checked (method, obj, params, &error);
2885 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
2891 * mono_runtime_try_invoke:
2892 * \param method method to invoke
2893 * \param obj object instance
2894 * \param params arguments to the method
2895 * \param exc exception information.
2896 * \param error set on error
2897 * Invokes the method represented by \p method on the object \p obj.
2899 * \p obj is the \c this pointer, it should be NULL for static
2900 * methods, a \c MonoObject* for object instances and a pointer to
2901 * the value type for value types.
2903 * The params array contains the arguments to the method with the
2904 * same convention: \c MonoObject* pointers for object instances and
2905 * pointers to the value type otherwise.
2907 * From unmanaged code you'll usually use the
2908 * mono_runtime_invoke() variant.
2910 * Note that this function doesn't handle virtual methods for
2911 * you, it will exec the exact method you pass: we still need to
2912 * expose a function to lookup the derived class implementation
2913 * of a virtual method (there are examples of this in the code,
2916 * For this function, you must not pass NULL as the \p exc argument if
2917 * you don't want to catch exceptions, use
2918 * mono_runtime_invoke_checked(). If an exception is thrown, you
2919 * can't use the \c MonoObject* result from the function.
2921 * If this method cannot be invoked, \p error will be set and \p exc and
2922 * the return value must not be used.
2924 * If the method returns a value type, it is boxed in an object
2928 mono_runtime_try_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError* error)
2930 MONO_REQ_GC_UNSAFE_MODE;
2932 g_assert (exc != NULL);
2934 if (mono_runtime_get_no_exec ())
2935 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2937 return do_runtime_invoke (method, obj, params, exc, error);
2941 * mono_runtime_invoke_checked:
2942 * \param method method to invoke
2943 * \param obj object instance
2944 * \param params arguments to the method
2945 * \param error set on error
2946 * Invokes the method represented by \p method on the object \p obj.
2948 * \p obj is the \c this pointer, it should be NULL for static
2949 * methods, a \c MonoObject* for object instances and a pointer to
2950 * the value type for value types.
2952 * The \p params array contains the arguments to the method with the
2953 * same convention: \c MonoObject* pointers for object instances and
2954 * pointers to the value type otherwise.
2956 * From unmanaged code you'll usually use the
2957 * mono_runtime_invoke() variant.
2959 * Note that this function doesn't handle virtual methods for
2960 * you, it will exec the exact method you pass: we still need to
2961 * expose a function to lookup the derived class implementation
2962 * of a virtual method (there are examples of this in the code,
2965 * If an exception is thrown, you can't use the \c MonoObject* result
2966 * from the function.
2968 * If this method cannot be invoked, \p error will be set. If the
2969 * method throws an exception (and we're in coop mode) the exception
2970 * will be set in \p error.
2972 * If the method returns a value type, it is boxed in an object
2976 mono_runtime_invoke_checked (MonoMethod *method, void *obj, void **params, MonoError* error)
2978 MONO_REQ_GC_UNSAFE_MODE;
2980 if (mono_runtime_get_no_exec ())
2981 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2983 return do_runtime_invoke (method, obj, params, NULL, error);
2987 * mono_method_get_unmanaged_thunk:
2988 * \param method method to generate a thunk for.
2990 * Returns an \c unmanaged->managed thunk that can be used to call
2991 * a managed method directly from C.
2993 * The thunk's C signature closely matches the managed signature:
2995 * C#: <code>public bool Equals (object obj);</code>
2997 * C: <code>typedef MonoBoolean (*Equals)(MonoObject*, MonoObject*, MonoException**);</code>
2999 * The 1st (<code>this</code>) parameter must not be used with static methods:
3001 * C#: <code>public static bool ReferenceEquals (object a, object b);</code>
3003 * C: <code>typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*, MonoException**);</code>
3005 * The last argument must be a non-null \c MonoException* pointer.
3006 * It has "out" semantics. After invoking the thunk, \c *ex will be NULL if no
3007 * exception has been thrown in managed code. Otherwise it will point
3008 * to the \c MonoException* caught by the thunk. In this case, the result of
3009 * the thunk is undefined:
3012 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
3014 * MonoException *ex = NULL;
3016 * Equals func = mono_method_get_unmanaged_thunk (method);
3018 * MonoBoolean res = func (thisObj, objToCompare, &ex);
3022 * // handle exception
3027 * The calling convention of the thunk matches the platform's default
3028 * convention. This means that under Windows, C declarations must
3029 * contain the \c __stdcall attribute:
3031 * C: <code>typedef MonoBoolean (__stdcall *Equals)(MonoObject*, MonoObject*, MonoException**);</code>
3035 * Value type arguments and return values are treated as they were objects:
3037 * C#: <code>public static Rectangle Intersect (Rectangle a, Rectangle b);</code>
3038 * C: <code>typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);</code>
3040 * Arguments must be properly boxed upon trunk's invocation, while return
3041 * values must be unboxed.
3044 mono_method_get_unmanaged_thunk (MonoMethod *method)
3046 MONO_REQ_GC_NEUTRAL_MODE;
3047 MONO_REQ_API_ENTRYPOINT;
3052 g_assert (!mono_threads_is_coop_enabled ());
3054 MONO_ENTER_GC_UNSAFE;
3055 method = mono_marshal_get_thunk_invoke_wrapper (method);
3056 res = mono_compile_method_checked (method, &error);
3057 mono_error_cleanup (&error);
3058 MONO_EXIT_GC_UNSAFE;
3064 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
3066 MONO_REQ_GC_UNSAFE_MODE;
3070 /* object fields cannot be byref, so we don't need a
3072 gpointer *p = (gpointer*)dest;
3079 case MONO_TYPE_BOOLEAN:
3081 case MONO_TYPE_U1: {
3082 guint8 *p = (guint8*)dest;
3083 *p = value ? *(guint8*)value : 0;
3088 case MONO_TYPE_CHAR: {
3089 guint16 *p = (guint16*)dest;
3090 *p = value ? *(guint16*)value : 0;
3093 #if SIZEOF_VOID_P == 4
3098 case MONO_TYPE_U4: {
3099 gint32 *p = (gint32*)dest;
3100 *p = value ? *(gint32*)value : 0;
3103 #if SIZEOF_VOID_P == 8
3108 case MONO_TYPE_U8: {
3109 gint64 *p = (gint64*)dest;
3110 *p = value ? *(gint64*)value : 0;
3113 case MONO_TYPE_R4: {
3114 float *p = (float*)dest;
3115 *p = value ? *(float*)value : 0;
3118 case MONO_TYPE_R8: {
3119 double *p = (double*)dest;
3120 *p = value ? *(double*)value : 0;
3123 case MONO_TYPE_STRING:
3124 case MONO_TYPE_SZARRAY:
3125 case MONO_TYPE_CLASS:
3126 case MONO_TYPE_OBJECT:
3127 case MONO_TYPE_ARRAY:
3128 mono_gc_wbarrier_generic_store (dest, deref_pointer ? *(MonoObject **)value : (MonoObject *)value);
3130 case MONO_TYPE_FNPTR:
3131 case MONO_TYPE_PTR: {
3132 gpointer *p = (gpointer*)dest;
3133 *p = deref_pointer? *(gpointer*)value: value;
3136 case MONO_TYPE_VALUETYPE:
3137 /* note that 't' and 'type->type' can be different */
3138 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3139 t = mono_class_enum_basetype (type->data.klass)->type;
3142 MonoClass *klass = mono_class_from_mono_type (type);
3143 int size = mono_class_value_size (klass, NULL);
3145 mono_gc_bzero_atomic (dest, size);
3147 mono_gc_wbarrier_value_copy (dest, value, 1, klass);
3150 case MONO_TYPE_GENERICINST:
3151 t = type->data.generic_class->container_class->byval_arg.type;
3154 g_error ("got type %x", type->type);
3159 * mono_field_set_value:
3160 * \param obj Instance object
3161 * \param field \c MonoClassField describing the field to set
3162 * \param value The value to be set
3164 * Sets the value of the field described by \p field in the object instance \p obj
3165 * to the value passed in \p value. This method should only be used for instance
3166 * fields. For static fields, use \c mono_field_static_set_value.
3168 * The value must be in the native format of the field type.
3171 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3173 MONO_REQ_GC_UNSAFE_MODE;
3177 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3179 dest = (char*)obj + field->offset;
3180 mono_copy_value (field->type, dest, value, FALSE);
3184 * mono_field_static_set_value:
3185 * \param field \c MonoClassField describing the field to set
3186 * \param value The value to be set
3187 * Sets the value of the static field described by \p field
3188 * to the value passed in \p value.
3189 * The value must be in the native format of the field type.
3192 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3194 MONO_REQ_GC_UNSAFE_MODE;
3198 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3199 /* you cant set a constant! */
3200 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3202 if (field->offset == -1) {
3203 /* Special static */
3206 mono_domain_lock (vt->domain);
3207 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3208 mono_domain_unlock (vt->domain);
3209 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3211 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3213 mono_copy_value (field->type, dest, value, FALSE);
3217 * mono_vtable_get_static_field_data:
3219 * Internal use function: return a pointer to the memory holding the static fields
3220 * for a class or NULL if there are no static fields.
3221 * This is exported only for use by the debugger.
3224 mono_vtable_get_static_field_data (MonoVTable *vt)
3226 MONO_REQ_GC_NEUTRAL_MODE
3228 if (!vt->has_static_fields)
3230 return vt->vtable [vt->klass->vtable_size];
3234 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3236 MONO_REQ_GC_UNSAFE_MODE;
3240 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3241 if (field->offset == -1) {
3242 /* Special static */
3245 mono_domain_lock (vt->domain);
3246 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3247 mono_domain_unlock (vt->domain);
3248 src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3250 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3253 src = (guint8*)obj + field->offset;
3260 * mono_field_get_value:
3261 * \param obj Object instance
3262 * \param field \c MonoClassField describing the field to fetch information from
3263 * \param value pointer to the location where the value will be stored
3264 * Use this routine to get the value of the field \p field in the object
3267 * The pointer provided by value must be of the field type, for reference
3268 * types this is a \c MonoObject*, for value types its the actual pointer to
3276 * mono_field_get_value (obj, int_field, &i);
3280 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3282 MONO_REQ_GC_UNSAFE_MODE;
3288 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3290 src = (char*)obj + field->offset;
3291 mono_copy_value (field->type, value, src, TRUE);
3295 * mono_field_get_value_object:
3296 * \param domain domain where the object will be created (if boxing)
3297 * \param field \c MonoClassField describing the field to fetch information from
3298 * \param obj The object instance for the field.
3299 * \returns a new \c MonoObject with the value from the given field. If the
3300 * field represents a value type, the value is boxed.
3303 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3306 MonoObject* result = mono_field_get_value_object_checked (domain, field, obj, &error);
3307 mono_error_assert_ok (&error);
3312 * mono_field_get_value_object_checked:
3313 * \param domain domain where the object will be created (if boxing)
3314 * \param field \c MonoClassField describing the field to fetch information from
3315 * \param obj The object instance for the field.
3316 * \param error Set on error.
3317 * \returns a new \c MonoObject with the value from the given field. If the
3318 * field represents a value type, the value is boxed. On error returns NULL and sets \p error.
3321 mono_field_get_value_object_checked (MonoDomain *domain, MonoClassField *field, MonoObject *obj, MonoError *error)
3323 MONO_REQ_GC_UNSAFE_MODE;
3329 MonoVTable *vtable = NULL;
3331 gboolean is_static = FALSE;
3332 gboolean is_ref = FALSE;
3333 gboolean is_literal = FALSE;
3334 gboolean is_ptr = FALSE;
3335 MonoType *type = mono_field_get_type_checked (field, error);
3337 return_val_if_nok (error, NULL);
3339 switch (type->type) {
3340 case MONO_TYPE_STRING:
3341 case MONO_TYPE_OBJECT:
3342 case MONO_TYPE_CLASS:
3343 case MONO_TYPE_ARRAY:
3344 case MONO_TYPE_SZARRAY:
3349 case MONO_TYPE_BOOLEAN:
3352 case MONO_TYPE_CHAR:
3361 case MONO_TYPE_VALUETYPE:
3362 is_ref = type->byref;
3364 case MONO_TYPE_GENERICINST:
3365 is_ref = !mono_type_generic_inst_is_valuetype (type);
3371 g_error ("type 0x%x not handled in "
3372 "mono_field_get_value_object", type->type);
3376 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3379 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3383 vtable = mono_class_vtable_full (domain, field->parent, error);
3384 return_val_if_nok (error, NULL);
3386 if (!vtable->initialized) {
3387 mono_runtime_class_init_full (vtable, error);
3388 return_val_if_nok (error, NULL);
3397 get_default_field_value (domain, field, &o, error);
3398 return_val_if_nok (error, NULL);
3399 } else if (is_static) {
3400 mono_field_static_get_value_checked (vtable, field, &o, error);
3401 return_val_if_nok (error, NULL);
3403 mono_field_get_value (obj, field, &o);
3409 static MonoMethod *m;
3415 MonoClass *ptr_klass = mono_class_get_pointer_class ();
3416 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3422 get_default_field_value (domain, field, v, error);
3423 return_val_if_nok (error, NULL);
3424 } else if (is_static) {
3425 mono_field_static_get_value_checked (vtable, field, v, error);
3426 return_val_if_nok (error, NULL);
3428 mono_field_get_value (obj, field, v);
3431 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3432 args [0] = ptr ? *ptr : NULL;
3433 args [1] = mono_type_get_object_checked (mono_domain_get (), type, error);
3434 return_val_if_nok (error, NULL);
3436 o = mono_runtime_invoke_checked (m, NULL, args, error);
3437 return_val_if_nok (error, NULL);
3442 /* boxed value type */
3443 klass = mono_class_from_mono_type (type);
3445 if (mono_class_is_nullable (klass))
3446 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass, error);
3448 o = mono_object_new_checked (domain, klass, error);
3449 return_val_if_nok (error, NULL);
3450 v = ((gchar *) o) + sizeof (MonoObject);
3453 get_default_field_value (domain, field, v, error);
3454 return_val_if_nok (error, NULL);
3455 } else if (is_static) {
3456 mono_field_static_get_value_checked (vtable, field, v, error);
3457 return_val_if_nok (error, NULL);
3459 mono_field_get_value (obj, field, v);
3466 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value, MonoError *error)
3468 MONO_REQ_GC_UNSAFE_MODE;
3472 const char *p = blob;
3473 mono_metadata_decode_blob_size (p, &p);
3476 case MONO_TYPE_BOOLEAN:
3479 *(guint8 *) value = *p;
3481 case MONO_TYPE_CHAR:
3484 *(guint16*) value = read16 (p);
3488 *(guint32*) value = read32 (p);
3492 *(guint64*) value = read64 (p);
3495 readr4 (p, (float*) value);
3498 readr8 (p, (double*) value);
3500 case MONO_TYPE_STRING:
3501 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob, error);
3503 case MONO_TYPE_CLASS:
3504 *(gpointer*) value = NULL;
3508 g_warning ("type 0x%02x should not be in constant table", type);
3514 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error)
3516 MONO_REQ_GC_NEUTRAL_MODE;
3518 MonoTypeEnum def_type;
3523 data = mono_class_get_field_default_value (field, &def_type);
3524 mono_get_constant_value_from_blob (domain, def_type, data, value, error);
3528 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3530 MONO_REQ_GC_UNSAFE_MODE;
3536 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3538 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3539 get_default_field_value (vt->domain, field, value, error);
3543 if (field->offset == -1) {
3544 /* Special static */
3545 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3546 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3548 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3550 mono_copy_value (field->type, value, src, TRUE);
3554 * mono_field_static_get_value:
3555 * \param vt vtable to the object
3556 * \param field \c MonoClassField describing the field to fetch information from
3557 * \param value where the value is returned
3558 * Use this routine to get the value of the static field \p field value.
3560 * The pointer provided by value must be of the field type, for reference
3561 * types this is a \c MonoObject*, for value types its the actual pointer to
3569 * mono_field_static_get_value (vt, int_field, &i);
3573 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3575 MONO_REQ_GC_NEUTRAL_MODE;
3578 mono_field_static_get_value_checked (vt, field, value, &error);
3579 mono_error_cleanup (&error);
3583 * mono_field_static_get_value_checked:
3584 * \param vt vtable to the object
3585 * \param field \c MonoClassField describing the field to fetch information from
3586 * \param value where the value is returned
3587 * \param error set on error
3588 * Use this routine to get the value of the static field \p field value.
3590 * The pointer provided by value must be of the field type, for reference
3591 * types this is a \c MonoObject*, for value types its the actual pointer to
3596 * mono_field_static_get_value_checked (vt, int_field, &i, error);
3597 * if (!is_ok (error)) { ... }
3599 * On failure sets \p error.
3602 mono_field_static_get_value_checked (MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3604 MONO_REQ_GC_NEUTRAL_MODE;
3606 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value, error);
3610 * mono_property_set_value:
3611 * \param prop MonoProperty to set
3612 * \param obj instance object on which to act
3613 * \param params parameters to pass to the propery
3614 * \param exc optional exception
3615 * Invokes the property's set method with the given arguments on the
3616 * object instance obj (or NULL for static properties).
3618 * You can pass NULL as the exc argument if you don't want to
3619 * catch exceptions, otherwise, \c *exc will be set to the exception
3620 * thrown, if any. if an exception is thrown, you can't use the
3621 * \c MonoObject* result from the function.
3624 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3626 MONO_REQ_GC_UNSAFE_MODE;
3629 do_runtime_invoke (prop->set, obj, params, exc, &error);
3630 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3631 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3633 mono_error_cleanup (&error);
3638 * mono_property_set_value_checked:
3639 * \param prop \c MonoProperty to set
3640 * \param obj instance object on which to act
3641 * \param params parameters to pass to the propery
3642 * \param error set on error
3643 * Invokes the property's set method with the given arguments on the
3644 * object instance \p obj (or NULL for static properties).
3645 * \returns TRUE on success. On failure returns FALSE and sets \p error.
3646 * If an exception is thrown, it will be caught and returned via \p error.
3649 mono_property_set_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3651 MONO_REQ_GC_UNSAFE_MODE;
3656 do_runtime_invoke (prop->set, obj, params, &exc, error);
3657 if (exc != NULL && is_ok (error))
3658 mono_error_set_exception_instance (error, (MonoException*)exc);
3659 return is_ok (error);
3663 * mono_property_get_value:
3664 * \param prop \c MonoProperty to fetch
3665 * \param obj instance object on which to act
3666 * \param params parameters to pass to the propery
3667 * \param exc optional exception
3668 * Invokes the property's \c get method with the given arguments on the
3669 * object instance \p obj (or NULL for static properties).
3671 * You can pass NULL as the \p exc argument if you don't want to
3672 * catch exceptions, otherwise, \c *exc will be set to the exception
3673 * thrown, if any. if an exception is thrown, you can't use the
3674 * \c MonoObject* result from the function.
3676 * \returns the value from invoking the \c get method on the property.
3679 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3681 MONO_REQ_GC_UNSAFE_MODE;
3684 MonoObject *val = do_runtime_invoke (prop->get, obj, params, exc, &error);
3685 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3686 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3688 mono_error_cleanup (&error); /* FIXME don't raise here */
3695 * mono_property_get_value_checked:
3696 * \param prop \c MonoProperty to fetch
3697 * \param obj instance object on which to act
3698 * \param params parameters to pass to the propery
3699 * \param error set on error
3700 * Invokes the property's \c get method with the given arguments on the
3701 * object instance obj (or NULL for static properties).
3703 * If an exception is thrown, you can't use the
3704 * \c MonoObject* result from the function. The exception will be propagated via \p error.
3706 * \returns the value from invoking the get method on the property. On
3707 * failure returns NULL and sets \p error.
3710 mono_property_get_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3712 MONO_REQ_GC_UNSAFE_MODE;
3715 MonoObject *val = do_runtime_invoke (prop->get, obj, params, &exc, error);
3716 if (exc != NULL && !is_ok (error))
3717 mono_error_set_exception_instance (error, (MonoException*) exc);
3725 * mono_nullable_init:
3726 * @buf: The nullable structure to initialize.
3727 * @value: the value to initialize from
3728 * @klass: the type for the object
3730 * Initialize the nullable structure pointed to by @buf from @value which
3731 * should be a boxed value type. The size of @buf should be able to hold
3732 * as much data as the @klass->instance_size (which is the number of bytes
3733 * that will be copies).
3735 * Since Nullables have variable structure, we can not define a C
3736 * structure for them.
3739 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3741 MONO_REQ_GC_UNSAFE_MODE;
3743 MonoClass *param_class = klass->cast_class;
3745 mono_class_setup_fields (klass);
3746 g_assert (klass->fields_inited);
3748 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3749 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3751 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3753 if (param_class->has_references)
3754 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3756 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3758 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3763 * mono_nullable_box:
3764 * \param buf The buffer representing the data to be boxed
3765 * \param klass the type to box it as.
3766 * \param error set on error
3768 * Creates a boxed vtype or NULL from the \c Nullable structure pointed to by
3769 * \p buf. On failure returns NULL and sets \p error.
3772 mono_nullable_box (guint8 *buf, MonoClass *klass, MonoError *error)
3774 MONO_REQ_GC_UNSAFE_MODE;
3777 MonoClass *param_class = klass->cast_class;
3779 mono_class_setup_fields (klass);
3780 g_assert (klass->fields_inited);
3782 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3783 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3785 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3786 MonoObject *o = mono_object_new_checked (mono_domain_get (), param_class, error);
3787 return_val_if_nok (error, NULL);
3788 if (param_class->has_references)
3789 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3791 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3799 * mono_get_delegate_invoke:
3800 * \param klass The delegate class
3801 * \returns the \c MonoMethod for the \c Invoke method in the delegate class or NULL if \p klass is a broken delegate type
3804 mono_get_delegate_invoke (MonoClass *klass)
3806 MONO_REQ_GC_NEUTRAL_MODE;
3810 /* This is called at runtime, so avoid the slower search in metadata */
3811 mono_class_setup_methods (klass);
3812 if (mono_class_has_failure (klass))
3814 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3819 * mono_get_delegate_begin_invoke:
3820 * \param klass The delegate class
3821 * \returns the \c MonoMethod for the \c BeginInvoke method in the delegate class or NULL if \p klass is a broken delegate type
3824 mono_get_delegate_begin_invoke (MonoClass *klass)
3826 MONO_REQ_GC_NEUTRAL_MODE;
3830 /* This is called at runtime, so avoid the slower search in metadata */
3831 mono_class_setup_methods (klass);
3832 if (mono_class_has_failure (klass))
3834 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3839 * mono_get_delegate_end_invoke:
3840 * \param klass The delegate class
3841 * \returns the \c MonoMethod for the \c EndInvoke method in the delegate class or NULL if \p klass is a broken delegate type
3844 mono_get_delegate_end_invoke (MonoClass *klass)
3846 MONO_REQ_GC_NEUTRAL_MODE;
3850 /* This is called at runtime, so avoid the slower search in metadata */
3851 mono_class_setup_methods (klass);
3852 if (mono_class_has_failure (klass))
3854 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3859 * mono_runtime_delegate_invoke:
3860 * \param delegate pointer to a delegate object.
3861 * \param params parameters for the delegate.
3862 * \param exc Pointer to the exception result.
3864 * Invokes the delegate method \p delegate with the parameters provided.
3866 * You can pass NULL as the \p exc argument if you don't want to
3867 * catch exceptions, otherwise, \c *exc will be set to the exception
3868 * thrown, if any. if an exception is thrown, you can't use the
3869 * \c MonoObject* result from the function.
3872 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3874 MONO_REQ_GC_UNSAFE_MODE;
3878 MonoObject *result = mono_runtime_delegate_try_invoke (delegate, params, exc, &error);
3880 mono_error_cleanup (&error);
3883 if (!is_ok (&error))
3884 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
3888 MonoObject *result = mono_runtime_delegate_invoke_checked (delegate, params, &error);
3889 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
3895 * mono_runtime_delegate_try_invoke:
3896 * \param delegate pointer to a delegate object.
3897 * \param params parameters for the delegate.
3898 * \param exc Pointer to the exception result.
3899 * \param error set on error
3900 * Invokes the delegate method \p delegate with the parameters provided.
3902 * You can pass NULL as the \p exc argument if you don't want to
3903 * catch exceptions, otherwise, \c *exc will be set to the exception
3904 * thrown, if any. On failure to execute, \p error will be set.
3905 * if an exception is thrown, you can't use the
3906 * \c MonoObject* result from the function.
3909 mono_runtime_delegate_try_invoke (MonoObject *delegate, void **params, MonoObject **exc, MonoError *error)
3911 MONO_REQ_GC_UNSAFE_MODE;
3915 MonoClass *klass = delegate->vtable->klass;
3918 im = mono_get_delegate_invoke (klass);
3920 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3923 o = mono_runtime_try_invoke (im, delegate, params, exc, error);
3925 o = mono_runtime_invoke_checked (im, delegate, params, error);
3932 * mono_runtime_delegate_invoke_checked:
3933 * \param delegate pointer to a delegate object.
3934 * \param params parameters for the delegate.
3935 * \param error set on error
3936 * Invokes the delegate method \p delegate with the parameters provided.
3937 * On failure \p error will be set and you can't use the \c MonoObject*
3938 * result from the function.
3941 mono_runtime_delegate_invoke_checked (MonoObject *delegate, void **params, MonoError *error)
3944 return mono_runtime_delegate_try_invoke (delegate, params, NULL, error);
3947 static char **main_args = NULL;
3948 static int num_main_args = 0;
3951 * mono_runtime_get_main_args:
3952 * \returns A \c MonoArray with the arguments passed to the main program
3955 mono_runtime_get_main_args (void)
3957 MONO_REQ_GC_UNSAFE_MODE;
3959 MonoArray *result = mono_runtime_get_main_args_checked (&error);
3960 mono_error_assert_ok (&error);
3965 * mono_runtime_get_main_args_checked:
3966 * \param error set on error
3967 * \returns a \c MonoArray with the arguments passed to the main
3968 * program. On failure returns NULL and sets \p error.
3971 mono_runtime_get_main_args_checked (MonoError *error)
3975 MonoDomain *domain = mono_domain_get ();
3979 res = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, num_main_args, error);
3980 return_val_if_nok (error, NULL);
3982 for (i = 0; i < num_main_args; ++i)
3983 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3989 free_main_args (void)
3991 MONO_REQ_GC_NEUTRAL_MODE;
3995 for (i = 0; i < num_main_args; ++i)
3996 g_free (main_args [i]);
4003 * mono_runtime_set_main_args:
4004 * \param argc number of arguments from the command line
4005 * \param argv array of strings from the command line
4006 * Set the command line arguments from an embedding application that doesn't otherwise call
4007 * \c mono_runtime_run_main.
4010 mono_runtime_set_main_args (int argc, char* argv[])
4012 MONO_REQ_GC_NEUTRAL_MODE;
4017 main_args = g_new0 (char*, argc);
4018 num_main_args = argc;
4020 for (i = 0; i < argc; ++i) {
4023 utf8_arg = mono_utf8_from_external (argv[i]);
4024 if (utf8_arg == NULL) {
4025 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
4026 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4030 main_args [i] = utf8_arg;
4037 * Prepare an array of arguments in order to execute a standard Main()
4038 * method (argc/argv contains the executable name). This method also
4039 * sets the command line argument value needed by System.Environment.
4043 prepare_run_main (MonoMethod *method, int argc, char *argv[])
4045 MONO_REQ_GC_UNSAFE_MODE;
4049 MonoArray *args = NULL;
4050 MonoDomain *domain = mono_domain_get ();
4051 gchar *utf8_fullpath;
4052 MonoMethodSignature *sig;
4054 g_assert (method != NULL);
4056 mono_thread_set_main (mono_thread_current ());
4058 main_args = g_new0 (char*, argc);
4059 num_main_args = argc;
4061 if (!g_path_is_absolute (argv [0])) {
4062 gchar *basename = g_path_get_basename (argv [0]);
4063 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
4067 utf8_fullpath = mono_utf8_from_external (fullpath);
4068 if(utf8_fullpath == NULL) {
4069 /* Printing the arg text will cause glib to
4070 * whinge about "Invalid UTF-8", but at least
4071 * its relevant, and shows the problem text
4074 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
4075 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4082 utf8_fullpath = mono_utf8_from_external (argv[0]);
4083 if(utf8_fullpath == NULL) {
4084 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
4085 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4090 main_args [0] = utf8_fullpath;
4092 for (i = 1; i < argc; ++i) {
4095 utf8_arg=mono_utf8_from_external (argv[i]);
4096 if(utf8_arg==NULL) {
4097 /* Ditto the comment about Invalid UTF-8 here */
4098 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
4099 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4103 main_args [i] = utf8_arg;
4108 sig = mono_method_signature (method);
4110 g_print ("Unable to load Main method.\n");
4114 if (sig->param_count) {
4115 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, argc, &error);
4116 mono_error_assert_ok (&error);
4117 for (i = 0; i < argc; ++i) {
4118 /* The encodings should all work, given that
4119 * we've checked all these args for the
4122 gchar *str = mono_utf8_from_external (argv [i]);
4123 MonoString *arg = mono_string_new (domain, str);
4124 mono_array_setref (args, i, arg);
4128 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, 0, &error);
4129 mono_error_assert_ok (&error);
4132 mono_assembly_set_main (method->klass->image->assembly);
4138 * mono_runtime_run_main:
4139 * \param method the method to start the application with (usually <code>Main</code>)
4140 * \param argc number of arguments from the command line
4141 * \param argv array of strings from the command line
4142 * \param exc excetption results
4143 * Execute a standard \c Main method (\p argc / \p argv contains the
4144 * executable name). This method also sets the command line argument value
4145 * needed by \c System.Environment.
4148 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
4151 MONO_REQ_GC_UNSAFE_MODE;
4154 MonoArray *args = prepare_run_main (method, argc, argv);
4157 res = mono_runtime_try_exec_main (method, args, exc);
4159 res = mono_runtime_exec_main_checked (method, args, &error);
4160 mono_error_raise_exception (&error); /* OK to throw, external only without a better alternative */
4166 * mono_runtime_run_main_checked:
4167 * \param method the method to start the application with (usually \c Main)
4168 * \param argc number of arguments from the command line
4169 * \param argv array of strings from the command line
4170 * \param error set on error
4172 * Execute a standard \c Main method (\p argc / \p argv contains the
4173 * executable name). This method also sets the command line argument value
4174 * needed by \c System.Environment. On failure sets \p error.
4177 mono_runtime_run_main_checked (MonoMethod *method, int argc, char* argv[],
4181 MonoArray *args = prepare_run_main (method, argc, argv);
4182 return mono_runtime_exec_main_checked (method, args, error);
4186 * mono_runtime_try_run_main:
4187 * \param method the method to start the application with (usually \c Main)
4188 * \param argc number of arguments from the command line
4189 * \param argv array of strings from the command line
4190 * \param exc set if \c Main throws an exception
4191 * \param error set if \c Main can't be executed
4192 * Execute a standard \c Main method (\p argc / \p argv contains the executable
4193 * name). This method also sets the command line argument value needed
4194 * by \c System.Environment. On failure sets \p error if Main can't be
4195 * executed or \p exc if it threw an exception.
4198 mono_runtime_try_run_main (MonoMethod *method, int argc, char* argv[],
4202 MonoArray *args = prepare_run_main (method, argc, argv);
4203 return mono_runtime_try_exec_main (method, args, exc);
4208 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4210 static MonoMethod *serialize_method;
4216 if (!serialize_method) {
4217 MonoClass *klass = mono_class_get_remoting_services_class ();
4218 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
4221 if (!serialize_method) {
4226 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
4231 array = mono_runtime_try_invoke (serialize_method, NULL, params, exc, &error);
4232 if (*exc == NULL && !mono_error_ok (&error))
4233 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert serialize_object to MonoError */
4235 mono_error_cleanup (&error);
4244 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4246 MONO_REQ_GC_UNSAFE_MODE;
4248 static MonoMethod *deserialize_method;
4254 if (!deserialize_method) {
4255 MonoClass *klass = mono_class_get_remoting_services_class ();
4256 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
4258 if (!deserialize_method) {
4266 result = mono_runtime_try_invoke (deserialize_method, NULL, params, exc, &error);
4267 if (*exc == NULL && !mono_error_ok (&error))
4268 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert deserialize_object to MonoError */
4270 mono_error_cleanup (&error);
4278 #ifndef DISABLE_REMOTING
4280 make_transparent_proxy (MonoObject *obj, MonoError *error)
4282 MONO_REQ_GC_UNSAFE_MODE;
4284 static MonoMethod *get_proxy_method;
4286 MonoDomain *domain = mono_domain_get ();
4287 MonoRealProxy *real_proxy;
4288 MonoReflectionType *reflection_type;
4289 MonoTransparentProxy *transparent_proxy;
4293 if (!get_proxy_method)
4294 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
4296 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
4298 real_proxy = (MonoRealProxy*) mono_object_new_checked (domain, mono_defaults.real_proxy_class, error);
4299 return_val_if_nok (error, NULL);
4300 reflection_type = mono_type_get_object_checked (domain, &obj->vtable->klass->byval_arg, error);
4301 return_val_if_nok (error, NULL);
4303 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
4304 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
4306 MonoObject *exc = NULL;
4308 transparent_proxy = (MonoTransparentProxy*) mono_runtime_try_invoke (get_proxy_method, real_proxy, NULL, &exc, error);
4309 if (exc != NULL && is_ok (error))
4310 mono_error_set_exception_instance (error, (MonoException*)exc);
4312 return (MonoObject*) transparent_proxy;
4314 #endif /* DISABLE_REMOTING */
4317 * mono_object_xdomain_representation
4318 * \param obj an object
4319 * \param target_domain a domain
4320 * \param error set on error.
4321 * Creates a representation of obj in the domain \p target_domain. This
4322 * is either a copy of \p obj arrived through via serialization and
4323 * deserialization or a proxy, depending on whether the object is
4324 * serializable or marshal by ref. \p obj must not be in \p target_domain.
4325 * If the object cannot be represented in \p target_domain, NULL is
4326 * returned and \p error is set appropriately.
4329 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoError *error)
4331 MONO_REQ_GC_UNSAFE_MODE;
4334 MonoObject *deserialized = NULL;
4336 #ifndef DISABLE_REMOTING
4337 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
4338 deserialized = make_transparent_proxy (obj, error);
4343 gboolean failure = FALSE;
4344 MonoDomain *domain = mono_domain_get ();
4345 MonoObject *serialized;
4346 MonoObject *exc = NULL;
4348 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
4349 serialized = serialize_object (obj, &failure, &exc);
4350 mono_domain_set_internal_with_options (target_domain, FALSE);
4352 deserialized = deserialize_object (serialized, &failure, &exc);
4353 if (domain != target_domain)
4354 mono_domain_set_internal_with_options (domain, FALSE);
4356 mono_error_set_exception_instance (error, (MonoException*)exc);
4359 return deserialized;
4362 /* Used in call_unhandled_exception_delegate */
4364 create_unhandled_exception_eventargs (MonoObject *exc, MonoError *error)
4366 MONO_REQ_GC_UNSAFE_MODE;
4371 MonoMethod *method = NULL;
4372 MonoBoolean is_terminating = TRUE;
4375 klass = mono_class_get_unhandled_exception_event_args_class ();
4376 mono_class_init (klass);
4378 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4379 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
4383 args [1] = &is_terminating;
4385 obj = mono_object_new_checked (mono_domain_get (), klass, error);
4386 return_val_if_nok (error, NULL);
4388 mono_runtime_invoke_checked (method, obj, args, error);
4389 return_val_if_nok (error, NULL);
4394 /* Used in mono_unhandled_exception */
4396 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4397 MONO_REQ_GC_UNSAFE_MODE;
4400 MonoObject *e = NULL;
4402 MonoDomain *current_domain = mono_domain_get ();
4404 if (domain != current_domain)
4405 mono_domain_set_internal_with_options (domain, FALSE);
4407 g_assert (domain == mono_object_domain (domain->domain));
4409 if (mono_object_domain (exc) != domain) {
4411 exc = mono_object_xdomain_representation (exc, domain, &error);
4413 if (!is_ok (&error)) {
4414 MonoError inner_error;
4415 MonoException *serialization_exc = mono_error_convert_to_exception (&error);
4416 exc = mono_object_xdomain_representation ((MonoObject*)serialization_exc, domain, &inner_error);
4417 mono_error_assert_ok (&inner_error);
4419 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4420 "System.Runtime.Serialization", "SerializationException",
4421 "Could not serialize unhandled exception.");
4425 g_assert (mono_object_domain (exc) == domain);
4427 pa [0] = domain->domain;
4428 pa [1] = create_unhandled_exception_eventargs (exc, &error);
4429 mono_error_assert_ok (&error);
4430 mono_runtime_delegate_try_invoke (delegate, pa, &e, &error);
4431 if (!is_ok (&error)) {
4433 e = (MonoObject*)mono_error_convert_to_exception (&error);
4435 mono_error_cleanup (&error);
4438 if (domain != current_domain)
4439 mono_domain_set_internal_with_options (current_domain, FALSE);
4442 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4443 if (!mono_error_ok (&error)) {
4444 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4445 mono_error_cleanup (&error);
4447 g_warning ("exception inside UnhandledException handler: %s\n", msg);
4453 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4456 * mono_runtime_unhandled_exception_policy_set:
4457 * \param policy the new policy
4458 * This is a VM internal routine.
4459 * Sets the runtime policy for handling unhandled exceptions.
4462 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4463 runtime_unhandled_exception_policy = policy;
4467 * mono_runtime_unhandled_exception_policy_get:
4469 * This is a VM internal routine.
4471 * Gets the runtime policy for handling unhandled exceptions.
4473 MonoRuntimeUnhandledExceptionPolicy
4474 mono_runtime_unhandled_exception_policy_get (void) {
4475 return runtime_unhandled_exception_policy;
4479 * mono_unhandled_exception:
4480 * \param exc exception thrown
4481 * This is a VM internal routine.
4483 * We call this function when we detect an unhandled exception
4484 * in the default domain.
4486 * It invokes the \c UnhandledException event in \c AppDomain or prints
4487 * a warning to the console
4490 mono_unhandled_exception (MonoObject *exc_raw)
4493 HANDLE_FUNCTION_ENTER ();
4494 MONO_HANDLE_DCL (MonoObject, exc);
4495 error_init (&error);
4496 mono_unhandled_exception_checked (exc, &error);
4497 mono_error_assert_ok (&error);
4498 HANDLE_FUNCTION_RETURN ();
4502 * mono_unhandled_exception:
4503 * @exc: exception thrown
4505 * This is a VM internal routine.
4507 * We call this function when we detect an unhandled exception
4508 * in the default domain.
4510 * It invokes the * UnhandledException event in AppDomain or prints
4511 * a warning to the console
4514 mono_unhandled_exception_checked (MonoObjectHandle exc, MonoError *error)
4516 MONO_REQ_GC_UNSAFE_MODE;
4519 MonoClassField *field;
4520 MonoDomain *current_domain, *root_domain;
4521 MonoObjectHandle current_appdomain_delegate = MONO_HANDLE_NEW (MonoObject, NULL);
4523 MonoClass *klass = mono_handle_class (exc);
4524 if (mono_class_has_parent (klass, mono_defaults.threadabortexception_class))
4527 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4530 current_domain = mono_domain_get ();
4531 root_domain = mono_get_root_domain ();
4533 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 */
4534 return_if_nok (error);
4535 if (current_domain != root_domain) {
4536 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 */
4537 return_if_nok (error);
4540 if (MONO_HANDLE_IS_NULL (current_appdomain_delegate) && MONO_HANDLE_IS_NULL (root_appdomain_delegate)) {
4541 mono_print_unhandled_exception (MONO_HANDLE_RAW (exc)); /* FIXME use handles for mono_print_unhandled_exception */
4543 /* unhandled exception callbacks must not be aborted */
4544 mono_threads_begin_abort_protected_block ();
4545 if (!MONO_HANDLE_IS_NULL (root_appdomain_delegate))
4546 call_unhandled_exception_delegate (root_domain, MONO_HANDLE_RAW (root_appdomain_delegate), MONO_HANDLE_RAW (exc)); /* FIXME use handles in call_unhandled_exception_delegate */
4547 if (!MONO_HANDLE_IS_NULL (current_appdomain_delegate))
4548 call_unhandled_exception_delegate (current_domain, MONO_HANDLE_RAW (current_appdomain_delegate), MONO_HANDLE_RAW (exc));
4549 mono_threads_end_abort_protected_block ();
4552 /* set exitcode only if we will abort the process */
4553 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4554 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4556 mono_environment_exitcode_set (1);
4561 * mono_runtime_exec_managed_code:
4562 * \param domain Application domain
4563 * \param main_func function to invoke from the execution thread
4564 * \param main_args parameter to the main_func
4565 * Launch a new thread to execute a function
4567 * \p main_func is called back from the thread with main_args as the
4568 * parameter. The callback function is expected to start \c Main
4569 * eventually. This function then waits for all managed threads to
4571 * It is not necessary anymore to execute managed code in a subthread,
4572 * so this function should not be used anymore by default: just
4573 * execute the code and then call mono_thread_manage().
4576 mono_runtime_exec_managed_code (MonoDomain *domain,
4577 MonoMainThreadFunc main_func,
4581 mono_thread_create_checked (domain, main_func, main_args, &error);
4582 mono_error_assert_ok (&error);
4584 mono_thread_manage ();
4588 prepare_thread_to_exec_main (MonoDomain *domain, MonoMethod *method)
4590 MonoInternalThread* thread = mono_thread_internal_current ();
4591 MonoCustomAttrInfo* cinfo;
4592 gboolean has_stathread_attribute;
4594 if (!domain->entry_assembly) {
4596 MonoAssembly *assembly;
4598 assembly = method->klass->image->assembly;
4599 domain->entry_assembly = assembly;
4600 /* Domains created from another domain already have application_base and configuration_file set */
4601 if (domain->setup->application_base == NULL) {
4602 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4605 if (domain->setup->configuration_file == NULL) {
4606 str = g_strconcat (assembly->image->name, ".config", NULL);
4607 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4609 mono_domain_set_options_from_config (domain);
4613 MonoError cattr_error;
4614 cinfo = mono_custom_attrs_from_method_checked (method, &cattr_error);
4615 mono_error_cleanup (&cattr_error); /* FIXME warn here? */
4617 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, mono_class_get_sta_thread_attribute_class ());
4619 mono_custom_attrs_free (cinfo);
4621 has_stathread_attribute = FALSE;
4623 if (has_stathread_attribute) {
4624 thread->apartment_state = ThreadApartmentState_STA;
4626 thread->apartment_state = ThreadApartmentState_MTA;
4628 mono_thread_init_apartment_state ();
4633 do_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4635 MONO_REQ_GC_UNSAFE_MODE;
4645 /* FIXME: check signature of method */
4646 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4648 res = mono_runtime_invoke_checked (method, NULL, pa, error);
4650 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4653 mono_environment_exitcode_set (rval);
4655 mono_runtime_invoke_checked (method, NULL, pa, error);
4667 do_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4669 MONO_REQ_GC_UNSAFE_MODE;
4679 /* FIXME: check signature of method */
4680 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4681 MonoError inner_error;
4683 res = mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4684 if (*exc == NULL && !mono_error_ok (&inner_error))
4685 *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4687 mono_error_cleanup (&inner_error);
4690 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4694 mono_environment_exitcode_set (rval);
4696 MonoError inner_error;
4697 mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4698 if (*exc == NULL && !mono_error_ok (&inner_error))
4699 *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4701 mono_error_cleanup (&inner_error);
4706 /* If the return type of Main is void, only
4707 * set the exitcode if an exception was thrown
4708 * (we don't want to blow away an
4709 * explicitly-set exit code)
4712 mono_environment_exitcode_set (rval);
4720 * Execute a standard Main() method (args doesn't contain the
4724 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4727 prepare_thread_to_exec_main (mono_object_domain (args), method);
4729 int rval = do_try_exec_main (method, args, exc);
4732 int rval = do_exec_main_checked (method, args, &error);
4733 mono_error_raise_exception (&error); /* OK to throw, external only with no better option */
4739 * Execute a standard Main() method (args doesn't contain the
4742 * On failure sets @error
4745 mono_runtime_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4748 prepare_thread_to_exec_main (mono_object_domain (args), method);
4749 return do_exec_main_checked (method, args, error);
4753 * Execute a standard Main() method (args doesn't contain the
4756 * On failure sets @error if Main couldn't be executed, or @exc if it threw an exception.
4759 mono_runtime_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4761 prepare_thread_to_exec_main (mono_object_domain (args), method);
4762 return do_try_exec_main (method, args, exc);
4767 /** invoke_array_extract_argument:
4768 * @params: array of arguments to the method.
4769 * @i: the index of the argument to extract.
4770 * @t: ith type from the method signature.
4771 * @has_byref_nullables: outarg - TRUE if method expects a byref nullable argument
4772 * @error: set on error.
4774 * Given an array of method arguments, return the ith one using the corresponding type
4775 * to perform necessary unboxing. If method expects a ref nullable argument, writes TRUE to @has_byref_nullables.
4777 * On failure sets @error and returns NULL.
4780 invoke_array_extract_argument (MonoArray *params, int i, MonoType *t, gboolean* has_byref_nullables, MonoError *error)
4782 MonoType *t_orig = t;
4783 gpointer result = NULL;
4789 case MONO_TYPE_BOOLEAN:
4792 case MONO_TYPE_CHAR:
4801 case MONO_TYPE_VALUETYPE:
4802 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (t_orig))) {
4803 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4804 result = mono_array_get (params, MonoObject*, i);
4806 *has_byref_nullables = TRUE;
4808 /* MS seems to create the objects if a null is passed in */
4809 gboolean was_null = FALSE;
4810 if (!mono_array_get (params, MonoObject*, i)) {
4811 MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (t_orig), error);
4812 return_val_if_nok (error, NULL);
4813 mono_array_setref (params, i, o);
4819 * We can't pass the unboxed vtype byref to the callee, since
4820 * that would mean the callee would be able to modify boxed
4821 * primitive types. So we (and MS) make a copy of the boxed
4822 * object, pass that to the callee, and replace the original
4823 * boxed object in the arg array with the copy.
4825 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4826 MonoObject *copy = mono_value_box_checked (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig), error);
4827 return_val_if_nok (error, NULL);
4828 mono_array_setref (params, i, copy);
4831 result = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4832 if (!t->byref && was_null)
4833 mono_array_setref (params, i, NULL);
4836 case MONO_TYPE_STRING:
4837 case MONO_TYPE_OBJECT:
4838 case MONO_TYPE_CLASS:
4839 case MONO_TYPE_ARRAY:
4840 case MONO_TYPE_SZARRAY:
4842 result = mono_array_addr (params, MonoObject*, i);
4843 // FIXME: I need to check this code path
4845 result = mono_array_get (params, MonoObject*, i);
4847 case MONO_TYPE_GENERICINST:
4849 t = &t->data.generic_class->container_class->this_arg;
4851 t = &t->data.generic_class->container_class->byval_arg;
4853 case MONO_TYPE_PTR: {
4856 /* The argument should be an IntPtr */
4857 arg = mono_array_get (params, MonoObject*, i);
4861 g_assert (arg->vtable->klass == mono_defaults.int_class);
4862 result = ((MonoIntPtr*)arg)->m_value;
4867 g_error ("type 0x%x not handled in mono_runtime_invoke_array", t_orig->type);
4872 * mono_runtime_invoke_array:
4873 * \param method method to invoke
4874 * \param obj object instance
4875 * \param params arguments to the method
4876 * \param exc exception information.
4877 * Invokes the method represented by \p method on the object \p obj.
4879 * \p obj is the \c this pointer, it should be NULL for static
4880 * methods, a \c MonoObject* for object instances and a pointer to
4881 * the value type for value types.
4883 * The \p params array contains the arguments to the method with the
4884 * same convention: \c MonoObject* pointers for object instances and
4885 * pointers to the value type otherwise. The \c _invoke_array
4886 * variant takes a C# \c object[] as the params argument (\c MonoArray*):
4887 * in this case the value types are boxed inside the
4888 * respective reference representation.
4890 * From unmanaged code you'll usually use the
4891 * mono_runtime_invoke_checked() variant.
4893 * Note that this function doesn't handle virtual methods for
4894 * you, it will exec the exact method you pass: we still need to
4895 * expose a function to lookup the derived class implementation
4896 * of a virtual method (there are examples of this in the code,
4899 * You can pass NULL as the \p exc argument if you don't want to
4900 * catch exceptions, otherwise, \c *exc will be set to the exception
4901 * thrown, if any. if an exception is thrown, you can't use the
4902 * \c MonoObject* result from the function.
4904 * If the method returns a value type, it is boxed in an object
4908 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4913 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, exc, &error);
4915 mono_error_cleanup (&error);
4918 if (!is_ok (&error))
4919 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
4923 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, NULL, &error);
4924 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
4930 * mono_runtime_invoke_array_checked:
4931 * \param method method to invoke
4932 * \param obj object instance
4933 * \param params arguments to the method
4934 * \param error set on failure.
4935 * Invokes the method represented by \p method on the object \p obj.
4937 * \p obj is the \c this pointer, it should be NULL for static
4938 * methods, a \c MonoObject* for object instances and a pointer to
4939 * the value type for value types.
4941 * The \p params array contains the arguments to the method with the
4942 * same convention: \c MonoObject* pointers for object instances and
4943 * pointers to the value type otherwise. The \c _invoke_array
4944 * variant takes a C# \c object[] as the \p params argument (\c MonoArray*):
4945 * in this case the value types are boxed inside the
4946 * respective reference representation.
4948 * From unmanaged code you'll usually use the
4949 * mono_runtime_invoke_checked() variant.
4951 * Note that this function doesn't handle virtual methods for
4952 * you, it will exec the exact method you pass: we still need to
4953 * expose a function to lookup the derived class implementation
4954 * of a virtual method (there are examples of this in the code,
4957 * On failure or exception, \p error will be set. In that case, you
4958 * can't use the \c MonoObject* result from the function.
4960 * If the method returns a value type, it is boxed in an object
4964 mono_runtime_invoke_array_checked (MonoMethod *method, void *obj, MonoArray *params,
4968 return mono_runtime_try_invoke_array (method, obj, params, NULL, error);
4972 * mono_runtime_try_invoke_array:
4973 * \param method method to invoke
4974 * \param obj object instance
4975 * \param params arguments to the method
4976 * \param exc exception information.
4977 * \param error set on failure.
4978 * Invokes the method represented by \p method on the object \p obj.
4980 * \p obj is the \c this pointer, it should be NULL for static
4981 * methods, a \c MonoObject* for object instances and a pointer to
4982 * the value type for value types.
4984 * The \p params array contains the arguments to the method with the
4985 * same convention: \c MonoObject* pointers for object instances and
4986 * pointers to the value type otherwise. The \c _invoke_array
4987 * variant takes a C# \c object[] as the params argument (\c MonoArray*):
4988 * in this case the value types are boxed inside the
4989 * respective reference representation.
4991 * From unmanaged code you'll usually use the
4992 * mono_runtime_invoke_checked() variant.
4994 * Note that this function doesn't handle virtual methods for
4995 * you, it will exec the exact method you pass: we still need to
4996 * expose a function to lookup the derived class implementation
4997 * of a virtual method (there are examples of this in the code,
5000 * You can pass NULL as the \p exc argument if you don't want to catch
5001 * exceptions, otherwise, \c *exc will be set to the exception thrown, if
5002 * any. On other failures, \p error will be set. If an exception is
5003 * thrown or there's an error, you can't use the \c MonoObject* result
5004 * from the function.
5006 * If the method returns a value type, it is boxed in an object
5010 mono_runtime_try_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
5011 MonoObject **exc, MonoError *error)
5013 MONO_REQ_GC_UNSAFE_MODE;
5017 MonoMethodSignature *sig = mono_method_signature (method);
5018 gpointer *pa = NULL;
5021 gboolean has_byref_nullables = FALSE;
5023 if (NULL != params) {
5024 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
5025 for (i = 0; i < mono_array_length (params); i++) {
5026 MonoType *t = sig->params [i];
5027 pa [i] = invoke_array_extract_argument (params, i, t, &has_byref_nullables, error);
5028 return_val_if_nok (error, NULL);
5032 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
5035 if (mono_class_is_nullable (method->klass)) {
5036 /* Need to create a boxed vtype instead */
5042 return mono_value_box_checked (mono_domain_get (), method->klass->cast_class, pa [0], error);
5047 obj = mono_object_new_checked (mono_domain_get (), method->klass, error);
5048 mono_error_assert_ok (error);
5049 g_assert (obj); /*maybe we should raise a TLE instead?*/
5050 #ifndef DISABLE_REMOTING
5051 if (mono_object_is_transparent_proxy (obj)) {
5052 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
5055 if (method->klass->valuetype)
5056 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
5059 } else if (method->klass->valuetype) {
5060 obj = mono_value_box_checked (mono_domain_get (), method->klass, obj, error);
5061 return_val_if_nok (error, NULL);
5065 mono_runtime_try_invoke (method, o, pa, exc, error);
5067 mono_runtime_invoke_checked (method, o, pa, error);
5070 return (MonoObject *)obj;
5072 if (mono_class_is_nullable (method->klass)) {
5073 MonoObject *nullable;
5075 /* Convert the unboxed vtype into a Nullable structure */
5076 nullable = mono_object_new_checked (mono_domain_get (), method->klass, error);
5077 return_val_if_nok (error, NULL);
5079 MonoObject *boxed = mono_value_box_checked (mono_domain_get (), method->klass->cast_class, obj, error);
5080 return_val_if_nok (error, NULL);
5081 mono_nullable_init ((guint8 *)mono_object_unbox (nullable), boxed, method->klass);
5082 obj = mono_object_unbox (nullable);
5085 /* obj must be already unboxed if needed */
5087 res = mono_runtime_try_invoke (method, obj, pa, exc, error);
5089 res = mono_runtime_invoke_checked (method, obj, pa, error);
5091 return_val_if_nok (error, NULL);
5093 if (sig->ret->type == MONO_TYPE_PTR) {
5094 MonoClass *pointer_class;
5095 static MonoMethod *box_method;
5097 MonoObject *box_exc;
5100 * The runtime-invoke wrapper returns a boxed IntPtr, need to
5101 * convert it to a Pointer object.
5103 pointer_class = mono_class_get_pointer_class ();
5105 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
5107 g_assert (res->vtable->klass == mono_defaults.int_class);
5108 box_args [0] = ((MonoIntPtr*)res)->m_value;
5109 box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, error);
5110 return_val_if_nok (error, NULL);
5112 res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, error);
5113 g_assert (box_exc == NULL);
5114 mono_error_assert_ok (error);
5117 if (has_byref_nullables) {
5119 * The runtime invoke wrapper already converted byref nullables back,
5120 * and stored them in pa, we just need to copy them back to the
5123 for (i = 0; i < mono_array_length (params); i++) {
5124 MonoType *t = sig->params [i];
5126 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
5127 mono_array_setref (params, i, pa [i]);
5137 * \param klass the class of the object that we want to create
5138 * \returns a newly created object whose definition is
5139 * looked up using \p klass. This will not invoke any constructors,
5140 * so the consumer of this routine has to invoke any constructors on
5141 * its own to initialize the object.
5143 * It returns NULL on failure.
5146 mono_object_new (MonoDomain *domain, MonoClass *klass)
5148 MONO_REQ_GC_UNSAFE_MODE;
5152 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5154 mono_error_cleanup (&error);
5159 ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
5161 MONO_REQ_GC_UNSAFE_MODE;
5165 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5167 mono_error_set_pending_exception (&error);
5172 * mono_object_new_checked:
5173 * \param klass the class of the object that we want to create
5174 * \param error set on error
5175 * \returns a newly created object whose definition is
5176 * looked up using \p klass. This will not invoke any constructors,
5177 * so the consumer of this routine has to invoke any constructors on
5178 * its own to initialize the object.
5180 * It returns NULL on failure and sets \p error.
5183 mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
5185 MONO_REQ_GC_UNSAFE_MODE;
5189 vtable = mono_class_vtable (domain, klass);
5190 g_assert (vtable); /* FIXME don't swallow the error */
5192 MonoObject *o = mono_object_new_specific_checked (vtable, error);
5197 * mono_object_new_pinned:
5199 * Same as mono_object_new, but the returned object will be pinned.
5200 * For SGEN, these objects will only be freed at appdomain unload.
5203 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
5205 MONO_REQ_GC_UNSAFE_MODE;
5211 vtable = mono_class_vtable (domain, klass);
5212 g_assert (vtable); /* FIXME don't swallow the error */
5214 MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
5216 if (G_UNLIKELY (!o))
5217 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
5218 else if (G_UNLIKELY (vtable->klass->has_finalize))
5219 mono_object_register_finalizer (o);
5225 * mono_object_new_specific:
5226 * \param vtable the vtable of the object that we want to create
5227 * \returns A newly created object with class and domain specified
5231 mono_object_new_specific (MonoVTable *vtable)
5234 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5235 mono_error_cleanup (&error);
5241 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
5243 MONO_REQ_GC_UNSAFE_MODE;
5249 /* check for is_com_object for COM Interop */
5250 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
5253 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
5256 MonoClass *klass = mono_class_get_activation_services_class ();
5259 mono_class_init (klass);
5261 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
5263 mono_error_set_not_supported (error, "Linked away.");
5266 vtable->domain->create_proxy_for_type_method = im;
5269 pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
5270 if (!mono_error_ok (error))
5273 o = mono_runtime_invoke_checked (im, NULL, pa, error);
5274 if (!mono_error_ok (error))
5281 return mono_object_new_alloc_specific_checked (vtable, error);
5285 ves_icall_object_new_specific (MonoVTable *vtable)
5288 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5289 mono_error_set_pending_exception (&error);
5295 * mono_object_new_alloc_specific:
5296 * \param vtable virtual table for the object.
5297 * This function allocates a new \c MonoObject with the type derived
5298 * from the \p vtable information. If the class of this object has a
5299 * finalizer, then the object will be tracked for finalization.
5301 * This method might raise an exception on errors. Use the
5302 * \c mono_object_new_fast_checked method if you want to manually raise
5305 * \returns the allocated object.
5308 mono_object_new_alloc_specific (MonoVTable *vtable)
5311 MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
5312 mono_error_cleanup (&error);
5318 * mono_object_new_alloc_specific_checked:
5319 * \param vtable virtual table for the object.
5320 * \param error holds the error return value.
5322 * This function allocates a new \c MonoObject with the type derived
5323 * from the \p vtable information. If the class of this object has a
5324 * finalizer, then the object will be tracked for finalization.
5326 * If there is not enough memory, the \p error parameter will be set
5327 * and will contain a user-visible message with the amount of bytes
5328 * that were requested.
5330 * \returns the allocated object, or NULL if there is not enough memory
5333 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
5335 MONO_REQ_GC_UNSAFE_MODE;
5341 o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5343 if (G_UNLIKELY (!o))
5344 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5345 else if (G_UNLIKELY (vtable->klass->has_finalize))
5346 mono_object_register_finalizer (o);
5352 * mono_object_new_fast:
5353 * \param vtable virtual table for the object.
5355 * This function allocates a new \c MonoObject with the type derived
5356 * from the \p vtable information. The returned object is not tracked
5357 * for finalization. If your object implements a finalizer, you should
5358 * use \c mono_object_new_alloc_specific instead.
5360 * This method might raise an exception on errors. Use the
5361 * \c mono_object_new_fast_checked method if you want to manually raise
5364 * \returns the allocated object.
5367 mono_object_new_fast (MonoVTable *vtable)
5370 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5371 mono_error_cleanup (&error);
5377 * mono_object_new_fast_checked:
5378 * \param vtable virtual table for the object.
5379 * \param error holds the error return value.
5381 * This function allocates a new \c MonoObject with the type derived
5382 * from the \p vtable information. The returned object is not tracked
5383 * for finalization. If your object implements a finalizer, you should
5384 * use \c mono_object_new_alloc_specific_checked instead.
5386 * If there is not enough memory, the \p error parameter will be set
5387 * and will contain a user-visible message with the amount of bytes
5388 * that were requested.
5390 * \returns the allocated object, or NULL if there is not enough memory
5393 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
5395 MONO_REQ_GC_UNSAFE_MODE;
5401 o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5403 if (G_UNLIKELY (!o))
5404 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5410 ves_icall_object_new_fast (MonoVTable *vtable)
5413 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5414 mono_error_set_pending_exception (&error);
5420 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
5422 MONO_REQ_GC_UNSAFE_MODE;
5428 o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
5430 if (G_UNLIKELY (!o))
5431 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5432 else if (G_UNLIKELY (vtable->klass->has_finalize))
5433 mono_object_register_finalizer (o);
5439 * mono_class_get_allocation_ftn:
5440 * \param vtable vtable
5441 * \param for_box the object will be used for boxing
5442 * \param pass_size_in_words Unused
5443 * \returns the allocation function appropriate for the given class.
5446 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
5448 MONO_REQ_GC_NEUTRAL_MODE;
5450 *pass_size_in_words = FALSE;
5452 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass))
5453 return ves_icall_object_new_specific;
5455 if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
5457 return ves_icall_object_new_fast;
5460 * FIXME: This is actually slower than ves_icall_object_new_fast, because
5461 * of the overhead of parameter passing.
5464 *pass_size_in_words = TRUE;
5465 #ifdef GC_REDIRECT_TO_LOCAL
5466 return GC_local_gcj_fast_malloc;
5468 return GC_gcj_fast_malloc;
5473 return ves_icall_object_new_specific;
5477 * mono_object_new_from_token:
5478 * \param image Context where the type_token is hosted
5479 * \param token a token of the type that we want to create
5480 * \returns A newly created object whose definition is
5481 * looked up using \p token in the \p image image
5484 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
5486 MONO_REQ_GC_UNSAFE_MODE;
5492 klass = mono_class_get_checked (image, token, &error);
5493 mono_error_assert_ok (&error);
5495 result = mono_object_new_checked (domain, klass, &error);
5497 mono_error_cleanup (&error);
5504 * mono_object_clone:
5505 * \param obj the object to clone
5506 * \returns A newly created object who is a shallow copy of \p obj
5509 mono_object_clone (MonoObject *obj)
5512 MonoObject *o = mono_object_clone_checked (obj, &error);
5513 mono_error_cleanup (&error);
5519 mono_object_clone_checked (MonoObject *obj, MonoError *error)
5521 MONO_REQ_GC_UNSAFE_MODE;
5528 size = obj->vtable->klass->instance_size;
5530 if (obj->vtable->klass->rank)
5531 return (MonoObject*)mono_array_clone_checked ((MonoArray*)obj, error);
5533 o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
5535 if (G_UNLIKELY (!o)) {
5536 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5540 /* If the object doesn't contain references this will do a simple memmove. */
5541 mono_gc_wbarrier_object_copy (o, obj);
5543 if (obj->vtable->klass->has_finalize)
5544 mono_object_register_finalizer (o);
5549 * mono_array_full_copy:
5550 * \param src source array to copy
5551 * \param dest destination array
5552 * Copies the content of one array to another with exactly the same type and size.
5555 mono_array_full_copy (MonoArray *src, MonoArray *dest)
5557 MONO_REQ_GC_UNSAFE_MODE;
5560 MonoClass *klass = src->obj.vtable->klass;
5562 g_assert (klass == dest->obj.vtable->klass);
5564 size = mono_array_length (src);
5565 g_assert (size == mono_array_length (dest));
5566 size *= mono_array_element_size (klass);
5568 array_full_copy_unchecked_size (src, dest, klass, size);
5572 array_full_copy_unchecked_size (MonoArray *src, MonoArray *dest, MonoClass *klass, uintptr_t size)
5575 if (klass->element_class->valuetype) {
5576 if (klass->element_class->has_references)
5577 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
5579 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5581 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
5584 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5589 * mono_array_clone_in_domain:
5590 * \param domain the domain in which the array will be cloned into
5591 * \param array the array to clone
5592 * \param error set on error
5593 * This routine returns a copy of the array that is hosted on the
5594 * specified \c MonoDomain. On failure returns NULL and sets \p error.
5597 mono_array_clone_in_domain (MonoDomain *domain, MonoArrayHandle array_handle, MonoError *error)
5599 MONO_REQ_GC_UNSAFE_MODE;
5601 MonoArrayHandle result = MONO_HANDLE_NEW (MonoArray, NULL);
5603 MonoClass *klass = mono_handle_class (array_handle);
5607 /* Pin source array here - if bounds is non-NULL, it's a pointer into the object data */
5608 uint32_t src_handle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, array_handle), TRUE);
5610 MonoArrayBounds *array_bounds = MONO_HANDLE_GETVAL (array_handle, bounds);
5612 if (array_bounds == NULL) {
5613 size = mono_array_handle_length (array_handle);
5614 o = mono_array_new_full_handle (domain, klass, &size, NULL, error);
5617 size *= mono_array_element_size (klass);
5619 uintptr_t *sizes = (uintptr_t *)alloca (klass->rank * sizeof (uintptr_t));
5620 intptr_t *lower_bounds = (intptr_t *)alloca (klass->rank * sizeof (intptr_t));
5621 size = mono_array_element_size (klass);
5622 for (int i = 0; i < klass->rank; ++i) {
5623 sizes [i] = array_bounds [i].length;
5624 size *= array_bounds [i].length;
5625 lower_bounds [i] = array_bounds [i].lower_bound;
5627 o = mono_array_new_full_handle (domain, klass, sizes, lower_bounds, error);
5632 uint32_t dst_handle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, o), TRUE);
5633 array_full_copy_unchecked_size (MONO_HANDLE_RAW (array_handle), MONO_HANDLE_RAW (o), klass, size);
5634 mono_gchandle_free (dst_handle);
5636 MONO_HANDLE_ASSIGN (result, o);
5639 mono_gchandle_free (src_handle);
5645 * \param array the array to clone
5646 * \returns A newly created array who is a shallow copy of \p array
5649 mono_array_clone (MonoArray *array)
5651 MONO_REQ_GC_UNSAFE_MODE;
5654 MonoArray *result = mono_array_clone_checked (array, &error);
5655 mono_error_cleanup (&error);
5660 * mono_array_clone_checked:
5661 * \param array the array to clone
5662 * \param error set on error
5663 * \returns A newly created array who is a shallow copy of \p array. On
5664 * failure returns NULL and sets \p error.
5667 mono_array_clone_checked (MonoArray *array_raw, MonoError *error)
5669 MONO_REQ_GC_UNSAFE_MODE;
5670 HANDLE_FUNCTION_ENTER ();
5671 /* FIXME: callers of mono_array_clone_checked should use handles */
5673 MONO_HANDLE_DCL (MonoArray, array);
5674 MonoArrayHandle result = mono_array_clone_in_domain (MONO_HANDLE_DOMAIN (array), array, error);
5675 HANDLE_FUNCTION_RETURN_OBJ (result);
5678 /* helper macros to check for overflow when calculating the size of arrays */
5679 #ifdef MONO_BIG_ARRAYS
5680 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
5681 #define MYGUINT_MAX MYGUINT64_MAX
5682 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5683 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
5684 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5685 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
5686 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
5688 #define MYGUINT32_MAX 4294967295U
5689 #define MYGUINT_MAX MYGUINT32_MAX
5690 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5691 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
5692 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5693 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
5694 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
5698 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
5700 MONO_REQ_GC_NEUTRAL_MODE;
5704 byte_len = mono_array_element_size (klass);
5705 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
5708 if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
5710 byte_len += MONO_SIZEOF_MONO_ARRAY;
5718 * mono_array_new_full:
5719 * \param domain domain where the object is created
5720 * \param array_class array class
5721 * \param lengths lengths for each dimension in the array
5722 * \param lower_bounds lower bounds for each dimension in the array (may be NULL)
5723 * This routine creates a new array object with the given dimensions,
5724 * lower bounds and type.
5727 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
5730 MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
5731 mono_error_cleanup (&error);
5737 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
5739 MONO_REQ_GC_UNSAFE_MODE;
5741 uintptr_t byte_len = 0, len, bounds_size;
5744 MonoArrayBounds *bounds;
5750 if (!array_class->inited)
5751 mono_class_init (array_class);
5755 /* A single dimensional array with a 0 lower bound is the same as an szarray */
5756 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
5758 if (len > MONO_ARRAY_MAX_INDEX) {
5759 mono_error_set_generic_error (error, "System", "OverflowException", "");
5764 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
5766 for (i = 0; i < array_class->rank; ++i) {
5767 if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
5768 mono_error_set_generic_error (error, "System", "OverflowException", "");
5771 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5772 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5779 if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5780 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5786 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5787 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5790 byte_len = (byte_len + 3) & ~3;
5791 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5792 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5795 byte_len += bounds_size;
5798 * Following three lines almost taken from mono_object_new ():
5799 * they need to be kept in sync.
5801 vtable = mono_class_vtable_full (domain, array_class, error);
5802 return_val_if_nok (error, NULL);
5805 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5807 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5809 if (G_UNLIKELY (!o)) {
5810 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5814 array = (MonoArray*)o;
5816 bounds = array->bounds;
5819 for (i = 0; i < array_class->rank; ++i) {
5820 bounds [i].length = lengths [i];
5822 bounds [i].lower_bound = lower_bounds [i];
5831 * \param domain domain where the object is created
5832 * \param eclass element class
5833 * \param n number of array elements
5834 * This routine creates a new szarray with \p n elements of type \p eclass.
5837 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5839 MONO_REQ_GC_UNSAFE_MODE;
5842 MonoArray *result = mono_array_new_checked (domain, eclass, n, &error);
5843 mono_error_cleanup (&error);
5848 * mono_array_new_checked:
5849 * \param domain domain where the object is created
5850 * \param eclass element class
5851 * \param n number of array elements
5852 * \param error set on error
5853 * This routine creates a new szarray with \p n elements of type \p eclass.
5854 * On failure returns NULL and sets \p error.
5857 mono_array_new_checked (MonoDomain *domain, MonoClass *eclass, uintptr_t n, MonoError *error)
5863 ac = mono_array_class_get (eclass, 1);
5866 MonoVTable *vtable = mono_class_vtable_full (domain, ac, error);
5867 return_val_if_nok (error, NULL);
5869 return mono_array_new_specific_checked (vtable, n, error);
5873 ves_icall_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5876 MonoArray *arr = mono_array_new_checked (domain, eclass, n, &error);
5877 mono_error_set_pending_exception (&error);
5883 * mono_array_new_specific:
5884 * \param vtable a vtable in the appropriate domain for an initialized class
5885 * \param n number of array elements
5886 * This routine is a fast alternative to \c mono_array_new for code which
5887 * can be sure about the domain it operates in.
5890 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5893 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5894 mono_error_cleanup (&error);
5900 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
5902 MONO_REQ_GC_UNSAFE_MODE;
5909 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
5910 mono_error_set_generic_error (error, "System", "OverflowException", "");
5914 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
5915 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5918 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
5920 if (G_UNLIKELY (!o)) {
5921 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5925 return (MonoArray*)o;
5929 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
5932 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5933 mono_error_set_pending_exception (&error);
5939 * mono_string_empty_wrapper:
5941 * Returns: The same empty string instance as the managed string.Empty
5944 mono_string_empty_wrapper (void)
5946 MonoDomain *domain = mono_domain_get ();
5947 return mono_string_empty (domain);
5951 * mono_string_empty:
5953 * Returns: The same empty string instance as the managed string.Empty
5956 mono_string_empty (MonoDomain *domain)
5959 g_assert (domain->empty_string);
5960 return domain->empty_string;
5964 * mono_string_new_utf16:
5965 * \param text a pointer to an utf16 string
5966 * \param len the length of the string
5967 * \returns A newly created string object which contains \p text.
5970 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
5972 MONO_REQ_GC_UNSAFE_MODE;
5975 MonoString *res = NULL;
5976 res = mono_string_new_utf16_checked (domain, text, len, &error);
5977 mono_error_cleanup (&error);
5983 * mono_string_new_utf16_checked:
5984 * \param text a pointer to an utf16 string
5985 * \param len the length of the string
5986 * \param error written on error.
5987 * \returns A newly created string object which contains \p text.
5988 * On error, returns NULL and sets \p error.
5991 mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
5993 MONO_REQ_GC_UNSAFE_MODE;
5999 s = mono_string_new_size_checked (domain, len, error);
6001 memcpy (mono_string_chars (s), text, len * 2);
6007 * mono_string_new_utf16_handle:
6008 * \param text a pointer to an utf16 string
6009 * \param len the length of the string
6010 * \param error written on error.
6011 * \returns A newly created string object which contains \p text.
6012 * On error, returns NULL and sets \p error.
6015 mono_string_new_utf16_handle (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
6017 return MONO_HANDLE_NEW (MonoString, mono_string_new_utf16_checked (domain, text, len, error));
6021 * mono_string_new_utf32_checked:
6022 * \param text a pointer to an utf32 string
6023 * \param len the length of the string
6024 * \param error set on failure.
6025 * \returns A newly created string object which contains \p text. On failure returns NULL and sets \p error.
6028 mono_string_new_utf32_checked (MonoDomain *domain, const mono_unichar4 *text, gint32 len, MonoError *error)
6030 MONO_REQ_GC_UNSAFE_MODE;
6033 mono_unichar2 *utf16_output = NULL;
6034 gint32 utf16_len = 0;
6035 GError *gerror = NULL;
6036 glong items_written;
6039 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
6042 g_error_free (gerror);
6044 while (utf16_output [utf16_len]) utf16_len++;
6046 s = mono_string_new_size_checked (domain, utf16_len, error);
6047 return_val_if_nok (error, NULL);
6049 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
6051 g_free (utf16_output);
6057 * mono_string_new_utf32:
6058 * \param text a pointer to a UTF-32 string
6059 * \param len the length of the string
6060 * \returns A newly created string object which contains \p text.
6063 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
6066 MonoString *result = mono_string_new_utf32_checked (domain, text, len, &error);
6067 mono_error_cleanup (&error);
6072 * mono_string_new_size:
6073 * \param text a pointer to a UTF-16 string
6074 * \param len the length of the string
6075 * \returns A newly created string object of \p len
6078 mono_string_new_size (MonoDomain *domain, gint32 len)
6081 MonoString *str = mono_string_new_size_checked (domain, len, &error);
6082 mono_error_cleanup (&error);
6088 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
6090 MONO_REQ_GC_UNSAFE_MODE;
6098 /* check for overflow */
6099 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
6100 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
6104 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
6105 g_assert (size > 0);
6107 vtable = mono_class_vtable (domain, mono_defaults.string_class);
6110 s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
6112 if (G_UNLIKELY (!s)) {
6113 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", size);
6121 * mono_string_new_len:
6122 * \param text a pointer to an utf8 string
6123 * \param length number of bytes in \p text to consider
6124 * \returns A newly created string object which contains \p text.
6127 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
6129 MONO_REQ_GC_UNSAFE_MODE;
6132 MonoString *result = mono_string_new_len_checked (domain, text, length, &error);
6133 mono_error_cleanup (&error);
6138 * mono_string_new_len_checked:
6139 * \param text a pointer to an utf8 string
6140 * \param length number of bytes in \p text to consider
6141 * \param error set on error
6142 * \returns A newly created string object which contains \p text. On
6143 * failure returns NULL and sets \p error.
6146 mono_string_new_len_checked (MonoDomain *domain, const char *text, guint length, MonoError *error)
6148 MONO_REQ_GC_UNSAFE_MODE;
6152 GError *eg_error = NULL;
6153 MonoString *o = NULL;
6155 glong items_written;
6157 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
6160 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6162 g_error_free (eg_error);
6171 * \param text a pointer to a UTF-8 string
6172 * \deprecated Use \c mono_string_new_checked in new code.
6173 * This function asserts if it cannot allocate a new string.
6174 * \returns A newly created string object which contains \p text.
6177 mono_string_new (MonoDomain *domain, const char *text)
6180 MonoString *res = NULL;
6181 res = mono_string_new_checked (domain, text, &error);
6182 mono_error_assert_ok (&error);
6187 * mono_string_new_checked:
6188 * \param text a pointer to an utf8 string
6189 * \param merror set on error
6190 * \returns A newly created string object which contains \p text.
6191 * On error returns NULL and sets \p merror.
6194 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
6196 MONO_REQ_GC_UNSAFE_MODE;
6198 GError *eg_error = NULL;
6199 MonoString *o = NULL;
6201 glong items_written;
6208 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &eg_error);
6211 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6213 mono_error_set_execution_engine (error, "String conversion error: %s", eg_error->message);
6218 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
6223 MonoString *o = NULL;
6225 if (!g_utf8_validate (text, -1, &end)) {
6226 mono_error_set_argument (error, "text", "Not a valid utf8 string");
6230 len = g_utf8_strlen (text, -1);
6231 o = mono_string_new_size_checked (domain, len, error);
6234 str = mono_string_chars (o);
6236 while (text < end) {
6237 *str++ = g_utf8_get_char (text);
6238 text = g_utf8_next_char (text);
6247 * mono_string_new_wrapper:
6248 * \param text pointer to UTF-8 characters.
6249 * Helper function to create a string object from \p text in the current domain.
6252 mono_string_new_wrapper (const char *text)
6254 MONO_REQ_GC_UNSAFE_MODE;
6256 MonoDomain *domain = mono_domain_get ();
6259 return mono_string_new (domain, text);
6266 * \param class the class of the value
6267 * \param value a pointer to the unboxed data
6268 * \returns A newly created object which contains \p value.
6271 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
6274 MonoObject *result = mono_value_box_checked (domain, klass, value, &error);
6275 mono_error_cleanup (&error);
6280 * mono_value_box_checked:
6281 * \param domain the domain of the new object
6282 * \param class the class of the value
6283 * \param value a pointer to the unboxed data
6284 * \param error set on error
6285 * \returns A newly created object which contains \p value. On failure
6286 * returns NULL and sets \p error.
6289 mono_value_box_checked (MonoDomain *domain, MonoClass *klass, gpointer value, MonoError *error)
6291 MONO_REQ_GC_UNSAFE_MODE;
6298 g_assert (klass->valuetype);
6299 if (mono_class_is_nullable (klass))
6300 return mono_nullable_box ((guint8 *)value, klass, error);
6302 vtable = mono_class_vtable (domain, klass);
6305 size = mono_class_instance_size (klass);
6306 res = mono_object_new_alloc_specific_checked (vtable, error);
6307 return_val_if_nok (error, NULL);
6309 size = size - sizeof (MonoObject);
6312 g_assert (size == mono_class_value_size (klass, NULL));
6313 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
6315 #if NO_UNALIGNED_ACCESS
6316 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6320 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
6323 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
6326 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
6329 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
6332 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6336 if (klass->has_finalize) {
6337 mono_object_register_finalizer (res);
6338 return_val_if_nok (error, NULL);
6345 * \param dest destination pointer
6346 * \param src source pointer
6347 * \param klass a valuetype class
6348 * Copy a valuetype from \p src to \p dest. This function must be used
6349 * when \p klass contains reference fields.
6352 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
6354 MONO_REQ_GC_UNSAFE_MODE;
6356 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
6360 * mono_value_copy_array:
6361 * \param dest destination array
6362 * \param dest_idx index in the \p dest array
6363 * \param src source pointer
6364 * \param count number of items
6365 * Copy \p count valuetype items from \p src to the array \p dest at index \p dest_idx.
6366 * This function must be used when \p klass contains references fields.
6367 * Overlap is handled.
6370 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
6372 MONO_REQ_GC_UNSAFE_MODE;
6374 int size = mono_array_element_size (dest->obj.vtable->klass);
6375 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
6376 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
6377 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
6381 * mono_object_get_domain:
6382 * \param obj object to query
6383 * \returns the \c MonoDomain where the object is hosted
6386 mono_object_get_domain (MonoObject *obj)
6388 MONO_REQ_GC_UNSAFE_MODE;
6390 return mono_object_domain (obj);
6394 * mono_object_get_class:
6395 * \param obj object to query
6396 * Use this function to obtain the \c MonoClass* for a given \c MonoObject.
6397 * \returns the \c MonoClass of the object.
6400 mono_object_get_class (MonoObject *obj)
6402 MONO_REQ_GC_UNSAFE_MODE;
6404 return mono_object_class (obj);
6407 * mono_object_get_size:
6408 * \param o object to query
6409 * \returns the size, in bytes, of \p o
6412 mono_object_get_size (MonoObject* o)
6414 MONO_REQ_GC_UNSAFE_MODE;
6416 MonoClass* klass = mono_object_class (o);
6417 if (klass == mono_defaults.string_class) {
6418 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
6419 } else if (o->vtable->rank) {
6420 MonoArray *array = (MonoArray*)o;
6421 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
6422 if (array->bounds) {
6425 size += sizeof (MonoArrayBounds) * o->vtable->rank;
6429 return mono_class_instance_size (klass);
6434 * mono_object_unbox:
6435 * \param obj object to unbox
6436 * \returns a pointer to the start of the valuetype boxed in this
6439 * This method will assert if the object passed is not a valuetype.
6442 mono_object_unbox (MonoObject *obj)
6444 MONO_REQ_GC_UNSAFE_MODE;
6446 /* add assert for valuetypes? */
6447 g_assert (obj->vtable->klass->valuetype);
6448 return ((char*)obj) + sizeof (MonoObject);
6452 * mono_object_isinst:
6453 * \param obj an object
6454 * \param klass a pointer to a class
6455 * \returns \p obj if \p obj is derived from \p klass or NULL otherwise.
6458 mono_object_isinst (MonoObject *obj_raw, MonoClass *klass)
6460 MONO_REQ_GC_UNSAFE_MODE;
6462 HANDLE_FUNCTION_ENTER ();
6463 MONO_HANDLE_DCL (MonoObject, obj);
6465 MonoObjectHandle result = mono_object_handle_isinst (obj, klass, &error);
6466 mono_error_cleanup (&error);
6467 HANDLE_FUNCTION_RETURN_OBJ (result);
6472 * mono_object_isinst_checked:
6473 * \param obj an object
6474 * \param klass a pointer to a class
6475 * \param error set on error
6476 * \returns \p obj if \p obj is derived from \p klass or NULL if it isn't.
6477 * On failure returns NULL and sets \p error.
6480 mono_object_isinst_checked (MonoObject *obj_raw, MonoClass *klass, MonoError *error)
6482 MONO_REQ_GC_UNSAFE_MODE;
6484 HANDLE_FUNCTION_ENTER ();
6486 MONO_HANDLE_DCL (MonoObject, obj);
6487 MonoObjectHandle result = mono_object_handle_isinst (obj, klass, error);
6488 HANDLE_FUNCTION_RETURN_OBJ (result);
6492 * mono_object_handle_isinst:
6493 * \param obj an object
6494 * \param klass a pointer to a class
6495 * \param error set on error
6496 * \returns \p obj if \p obj is derived from \p klass or NULL if it isn't.
6497 * On failure returns NULL and sets \p error.
6500 mono_object_handle_isinst (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
6505 mono_class_init (klass);
6507 if (mono_class_is_marshalbyref (klass) || mono_class_is_interface (klass)) {
6508 return mono_object_handle_isinst_mbyref (obj, klass, error);
6511 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6513 if (!MONO_HANDLE_IS_NULL (obj) && mono_class_is_assignable_from (klass, mono_handle_class (obj)))
6514 MONO_HANDLE_ASSIGN (result, obj);
6519 * mono_object_isinst_mbyref:
6522 mono_object_isinst_mbyref (MonoObject *obj_raw, MonoClass *klass)
6524 MONO_REQ_GC_UNSAFE_MODE;
6526 HANDLE_FUNCTION_ENTER ();
6528 MONO_HANDLE_DCL (MonoObject, obj);
6529 MonoObjectHandle result = mono_object_handle_isinst_mbyref (obj, klass, &error);
6530 mono_error_cleanup (&error); /* FIXME better API that doesn't swallow the error */
6531 HANDLE_FUNCTION_RETURN_OBJ (result);
6535 mono_object_handle_isinst_mbyref (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
6539 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6541 if (MONO_HANDLE_IS_NULL (obj))
6544 MonoVTable *vt = MONO_HANDLE_GETVAL (obj, vtable);
6546 if (mono_class_is_interface (klass)) {
6547 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
6548 MONO_HANDLE_ASSIGN (result, obj);
6552 /* casting an array one of the invariant interfaces that must act as such */
6553 if (klass->is_array_special_interface) {
6554 if (mono_class_is_assignable_from (klass, vt->klass)) {
6555 MONO_HANDLE_ASSIGN (result, obj);
6560 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
6561 else if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, mono_handle_class (obj))) {
6562 MONO_HANDLE_ASSIGN (result, obj);
6566 MonoClass *oklass = vt->klass;
6567 if (mono_class_is_transparent_proxy (oklass)){
6568 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), remote_class);
6569 oklass = remote_class->proxy_class;
6572 mono_class_setup_supertypes (klass);
6573 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass)) {
6574 MONO_HANDLE_ASSIGN (result, obj);
6578 #ifndef DISABLE_REMOTING
6579 if (mono_class_is_transparent_proxy (vt->klass))
6581 MonoBoolean custom_type_info = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), custom_type_info);
6582 if (!custom_type_info)
6584 MonoDomain *domain = mono_domain_get ();
6585 MonoObjectHandle rp = MONO_HANDLE_NEW (MonoObject, NULL);
6586 MONO_HANDLE_GET (rp, MONO_HANDLE_CAST (MonoTransparentProxy, obj), rp);
6587 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
6588 MonoMethod *im = NULL;
6591 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
6593 mono_error_set_not_supported (error, "Linked away.");
6596 im = mono_object_handle_get_virtual_method (rp, im, error);
6601 MonoReflectionTypeHandle reftype = mono_type_get_object_handle (domain, &klass->byval_arg, error);
6605 pa [0] = MONO_HANDLE_RAW (reftype);
6606 pa [1] = MONO_HANDLE_RAW (obj);
6607 MonoObject *res = mono_runtime_invoke_checked (im, MONO_HANDLE_RAW (rp), pa, error);
6611 if (*(MonoBoolean *) mono_object_unbox(res)) {
6612 /* Update the vtable of the remote type, so it can safely cast to this new type */
6613 mono_upgrade_remote_class (domain, obj, klass, error);
6616 MONO_HANDLE_ASSIGN (result, obj);
6619 #endif /* DISABLE_REMOTING */
6625 * mono_object_castclass_mbyref:
6626 * \param obj an object
6627 * \param klass a pointer to a class
6628 * \returns \p obj if \p obj is derived from \p klass, returns NULL otherwise.
6631 mono_object_castclass_mbyref (MonoObject *obj_raw, MonoClass *klass)
6633 MONO_REQ_GC_UNSAFE_MODE;
6634 HANDLE_FUNCTION_ENTER ();
6636 MONO_HANDLE_DCL (MonoObject, obj);
6637 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6638 if (MONO_HANDLE_IS_NULL (obj))
6640 MONO_HANDLE_ASSIGN (result, mono_object_handle_isinst_mbyref (obj, klass, &error));
6641 mono_error_cleanup (&error);
6643 HANDLE_FUNCTION_RETURN_OBJ (result);
6647 MonoDomain *orig_domain;
6653 str_lookup (MonoDomain *domain, gpointer user_data)
6655 MONO_REQ_GC_UNSAFE_MODE;
6657 LDStrInfo *info = (LDStrInfo *)user_data;
6658 if (info->res || domain == info->orig_domain)
6660 info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
6664 mono_string_get_pinned (MonoString *str, MonoError *error)
6666 MONO_REQ_GC_UNSAFE_MODE;
6670 /* We only need to make a pinned version of a string if this is a moving GC */
6671 if (!mono_gc_is_moving ())
6675 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
6676 news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
6678 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
6679 news->length = mono_string_length (str);
6681 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6687 mono_string_is_interned_lookup (MonoString *str, int insert, MonoError *error)
6689 MONO_REQ_GC_UNSAFE_MODE;
6691 MonoGHashTable *ldstr_table;
6692 MonoString *s, *res;
6697 domain = ((MonoObject *)str)->vtable->domain;
6698 ldstr_table = domain->ldstr_table;
6700 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6706 /* Allocate outside the lock */
6708 s = mono_string_get_pinned (str, error);
6709 return_val_if_nok (error, NULL);
6712 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6717 mono_g_hash_table_insert (ldstr_table, s, s);
6722 LDStrInfo ldstr_info;
6723 ldstr_info.orig_domain = domain;
6724 ldstr_info.ins = str;
6725 ldstr_info.res = NULL;
6727 mono_domain_foreach (str_lookup, &ldstr_info);
6728 if (ldstr_info.res) {
6730 * the string was already interned in some other domain:
6731 * intern it in the current one as well.
6733 mono_g_hash_table_insert (ldstr_table, str, str);
6743 * mono_string_is_interned:
6744 * \param o String to probe
6745 * \returns Whether the string has been interned.
6748 mono_string_is_interned (MonoString *o)
6751 MonoString *result = mono_string_is_interned_lookup (o, FALSE, &error);
6752 /* This function does not fail. */
6753 mono_error_assert_ok (&error);
6758 * mono_string_intern:
6759 * \param o String to intern
6760 * Interns the string passed.
6761 * \returns The interned string.
6764 mono_string_intern (MonoString *str)
6767 MonoString *result = mono_string_intern_checked (str, &error);
6768 mono_error_assert_ok (&error);
6773 * mono_string_intern_checked:
6774 * \param o String to intern
6775 * \param error set on error.
6776 * Interns the string passed.
6777 * \returns The interned string. On failure returns NULL and sets \p error
6780 mono_string_intern_checked (MonoString *str, MonoError *error)
6782 MONO_REQ_GC_UNSAFE_MODE;
6786 return mono_string_is_interned_lookup (str, TRUE, error);
6791 * \param domain the domain where the string will be used.
6792 * \param image a metadata context
6793 * \param idx index into the user string table.
6794 * Implementation for the \c ldstr opcode.
6795 * \returns a loaded string from the \p image / \p idx combination.
6798 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
6801 MonoString *result = mono_ldstr_checked (domain, image, idx, &error);
6802 mono_error_cleanup (&error);
6807 * mono_ldstr_checked:
6808 * \param domain the domain where the string will be used.
6809 * \param image a metadata context
6810 * \param idx index into the user string table.
6811 * \param error set on error.
6812 * Implementation for the \c ldstr opcode.
6813 * \returns A loaded string from the \p image / \p idx combination.
6814 * On failure returns NULL and sets \p error.
6817 mono_ldstr_checked (MonoDomain *domain, MonoImage *image, guint32 idx, MonoError *error)
6819 MONO_REQ_GC_UNSAFE_MODE;
6822 if (image->dynamic) {
6823 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL, error);
6826 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6827 return NULL; /*FIXME we should probably be raising an exception here*/
6828 MonoString *str = mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx), error);
6834 * mono_ldstr_metadata_sig
6835 * \param domain the domain for the string
6836 * \param sig the signature of a metadata string
6837 * \param error set on error
6838 * \returns a \c MonoString for a string stored in the metadata. On
6839 * failure returns NULL and sets \p error.
6842 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error)
6844 MONO_REQ_GC_UNSAFE_MODE;
6847 const char *str = sig;
6848 MonoString *o, *interned;
6851 len2 = mono_metadata_decode_blob_size (str, &str);
6854 o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, error);
6855 return_val_if_nok (error, NULL);
6856 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
6859 guint16 *p2 = (guint16*)mono_string_chars (o);
6860 for (i = 0; i < len2; ++i) {
6861 *p2 = GUINT16_FROM_LE (*p2);
6867 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6870 return interned; /* o will get garbage collected */
6872 o = mono_string_get_pinned (o, error);
6875 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6877 mono_g_hash_table_insert (domain->ldstr_table, o, o);
6889 * Same as mono_ldstr, but return a NULL terminated utf8 string instead
6893 mono_ldstr_utf8 (MonoImage *image, guint32 idx, MonoError *error)
6899 GError *gerror = NULL;
6903 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6904 return NULL; /*FIXME we should probably be raising an exception here*/
6905 str = mono_metadata_user_string (image, idx);
6907 len2 = mono_metadata_decode_blob_size (str, &str);
6910 as = g_utf16_to_utf8 ((guint16*)str, len2, NULL, &written, &gerror);
6912 mono_error_set_argument (error, "string", "%s", gerror->message);
6913 g_error_free (gerror);
6916 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6917 if (len2 > written) {
6918 /* allocate the total length and copy the part of the string that has been converted */
6919 char *as2 = (char *)g_malloc0 (len2);
6920 memcpy (as2, as, written);
6929 * mono_string_to_utf8:
6930 * \param s a \c System.String
6931 * \deprecated Use \c mono_string_to_utf8_checked to avoid having an exception arbitrarily raised.
6932 * \returns the UTF-8 representation for \p s.
6933 * The resulting buffer needs to be freed with \c mono_free().
6936 mono_string_to_utf8 (MonoString *s)
6938 MONO_REQ_GC_UNSAFE_MODE;
6941 char *result = mono_string_to_utf8_checked (s, &error);
6943 if (!is_ok (&error)) {
6944 mono_error_cleanup (&error);
6951 * mono_string_to_utf8_checked:
6952 * \param s a \c System.String
6953 * \param error a \c MonoError.
6954 * Converts a \c MonoString to its UTF-8 representation. May fail; check
6955 * \p error to determine whether the conversion was successful.
6956 * The resulting buffer should be freed with \c mono_free().
6959 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
6961 MONO_REQ_GC_UNSAFE_MODE;
6965 GError *gerror = NULL;
6973 return g_strdup ("");
6975 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
6977 mono_error_set_argument (error, "string", "%s", gerror->message);
6978 g_error_free (gerror);
6981 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6982 if (s->length > written) {
6983 /* allocate the total length and copy the part of the string that has been converted */
6984 char *as2 = (char *)g_malloc0 (s->length);
6985 memcpy (as2, as, written);
6994 mono_string_handle_to_utf8 (MonoStringHandle s, MonoError *error)
6996 return mono_string_to_utf8_checked (MONO_HANDLE_RAW (s), error);
7000 * mono_string_to_utf8_ignore:
7001 * \param s a MonoString
7002 * Converts a \c MonoString to its UTF-8 representation. Will ignore
7003 * invalid surrogate pairs.
7004 * The resulting buffer should be freed with \c mono_free().
7007 mono_string_to_utf8_ignore (MonoString *s)
7009 MONO_REQ_GC_UNSAFE_MODE;
7018 return g_strdup ("");
7020 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
7022 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
7023 if (s->length > written) {
7024 /* allocate the total length and copy the part of the string that has been converted */
7025 char *as2 = (char *)g_malloc0 (s->length);
7026 memcpy (as2, as, written);
7035 * mono_string_to_utf8_image_ignore:
7036 * \param s a \c System.String
7037 * Same as \c mono_string_to_utf8_ignore, but allocate the string from the image mempool.
7040 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
7042 MONO_REQ_GC_UNSAFE_MODE;
7044 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
7048 * mono_string_to_utf8_mp_ignore:
7049 * \param s a \c System.String
7050 * Same as \c mono_string_to_utf8_ignore, but allocate the string from a mempool.
7053 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
7055 MONO_REQ_GC_UNSAFE_MODE;
7057 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
7062 * mono_string_to_utf16:
7063 * \param s a \c MonoString
7064 * \returns a null-terminated array of the UTF-16 chars
7065 * contained in \p s. The result must be freed with \c g_free().
7066 * This is a temporary helper until our string implementation
7067 * is reworked to always include the null-terminating char.
7070 mono_string_to_utf16 (MonoString *s)
7072 MONO_REQ_GC_UNSAFE_MODE;
7079 as = (char *)g_malloc ((s->length * 2) + 2);
7080 as [(s->length * 2)] = '\0';
7081 as [(s->length * 2) + 1] = '\0';
7084 return (gunichar2 *)(as);
7087 memcpy (as, mono_string_chars(s), s->length * 2);
7088 return (gunichar2 *)(as);
7092 * mono_string_to_utf32:
7093 * \param s a \c MonoString
7094 * \returns a null-terminated array of the UTF-32 (UCS-4) chars
7095 * contained in \p s. The result must be freed with \c g_free().
7098 mono_string_to_utf32 (MonoString *s)
7100 MONO_REQ_GC_UNSAFE_MODE;
7102 mono_unichar4 *utf32_output = NULL;
7103 GError *error = NULL;
7104 glong items_written;
7109 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
7112 g_error_free (error);
7114 return utf32_output;
7118 * mono_string_from_utf16:
7119 * \param data the UTF-16 string (LPWSTR) to convert
7120 * Converts a NULL-terminated UTF-16 string (LPWSTR) to a \c MonoString.
7121 * \returns a \c MonoString.
7124 mono_string_from_utf16 (gunichar2 *data)
7127 MonoString *result = mono_string_from_utf16_checked (data, &error);
7128 mono_error_cleanup (&error);
7133 * mono_string_from_utf16_checked:
7134 * \param data the UTF-16 string (LPWSTR) to convert
7135 * \param error set on error
7136 * Converts a NULL-terminated UTF-16 string (LPWSTR) to a \c MonoString.
7137 * \returns a \c MonoString. On failure sets \p error and returns NULL.
7140 mono_string_from_utf16_checked (gunichar2 *data, MonoError *error)
7143 MONO_REQ_GC_UNSAFE_MODE;
7146 MonoDomain *domain = mono_domain_get ();
7152 while (data [len]) len++;
7154 return mono_string_new_utf16_checked (domain, data, len, error);
7158 * mono_string_from_utf32:
7159 * \param data the UTF-32 string (LPWSTR) to convert
7160 * Converts a UTF-32 (UCS-4) string to a \c MonoString.
7161 * \returns a \c MonoString.
7164 mono_string_from_utf32 (mono_unichar4 *data)
7167 MonoString *result = mono_string_from_utf32_checked (data, &error);
7168 mono_error_cleanup (&error);
7173 * mono_string_from_utf32_checked:
7174 * \param data the UTF-32 string (LPWSTR) to convert
7175 * \param error set on error
7176 * Converts a UTF-32 (UCS-4) string to a \c MonoString.
7177 * \returns a \c MonoString. On failure returns NULL and sets \p error.
7180 mono_string_from_utf32_checked (mono_unichar4 *data, MonoError *error)
7182 MONO_REQ_GC_UNSAFE_MODE;
7185 MonoString* result = NULL;
7186 mono_unichar2 *utf16_output = NULL;
7187 GError *gerror = NULL;
7188 glong items_written;
7194 while (data [len]) len++;
7196 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &gerror);
7199 g_error_free (gerror);
7201 result = mono_string_from_utf16_checked (utf16_output, error);
7202 g_free (utf16_output);
7207 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
7209 MONO_REQ_GC_UNSAFE_MODE;
7216 r = mono_string_to_utf8_ignore (s);
7218 r = mono_string_to_utf8_checked (s, error);
7219 if (!mono_error_ok (error))
7226 len = strlen (r) + 1;
7228 mp_s = (char *)mono_mempool_alloc (mp, len);
7230 mp_s = (char *)mono_image_alloc (image, len);
7232 memcpy (mp_s, r, len);
7240 * mono_string_to_utf8_image:
7241 * \param s a \c System.String
7242 * Same as \c mono_string_to_utf8, but allocate the string from the image mempool.
7245 mono_string_to_utf8_image (MonoImage *image, MonoStringHandle s, MonoError *error)
7247 MONO_REQ_GC_UNSAFE_MODE;
7249 return mono_string_to_utf8_internal (NULL, image, MONO_HANDLE_RAW (s), FALSE, error); /* FIXME pin the string */
7253 * mono_string_to_utf8_mp:
7254 * \param s a \c System.String
7255 * Same as \c mono_string_to_utf8, but allocate the string from a mempool.
7258 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
7260 MONO_REQ_GC_UNSAFE_MODE;
7262 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
7266 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
7269 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
7271 eh_callbacks = *cbs;
7274 MonoRuntimeExceptionHandlingCallbacks *
7275 mono_get_eh_callbacks (void)
7277 return &eh_callbacks;
7281 * mono_raise_exception:
7282 * \param ex exception object
7283 * Signal the runtime that the exception \p ex has been raised in unmanaged code.
7286 mono_raise_exception (MonoException *ex)
7288 MONO_REQ_GC_UNSAFE_MODE;
7291 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
7292 * that will cause gcc to omit the function epilog, causing problems when
7293 * the JIT tries to walk the stack, since the return address on the stack
7294 * will point into the next function in the executable, not this one.
7296 eh_callbacks.mono_raise_exception (ex);
7300 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
7302 MONO_REQ_GC_UNSAFE_MODE;
7304 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
7308 * mono_wait_handle_new:
7309 * \param domain Domain where the object will be created
7310 * \param handle Handle for the wait handle
7311 * \param error set on error.
7312 * \returns A new \c MonoWaitHandle created in the given domain for the
7313 * given handle. On failure returns NULL and sets \p error.
7316 mono_wait_handle_new (MonoDomain *domain, HANDLE handle, MonoError *error)
7318 MONO_REQ_GC_UNSAFE_MODE;
7320 MonoWaitHandle *res;
7321 gpointer params [1];
7322 static MonoMethod *handle_set;
7325 res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, error);
7326 return_val_if_nok (error, NULL);
7328 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
7330 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
7332 params [0] = &handle;
7334 mono_runtime_invoke_checked (handle_set, res, params, error);
7339 mono_wait_handle_get_handle (MonoWaitHandle *handle)
7341 MONO_REQ_GC_UNSAFE_MODE;
7343 static MonoClassField *f_safe_handle = NULL;
7346 if (!f_safe_handle) {
7347 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safeWaitHandle");
7348 g_assert (f_safe_handle);
7351 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
7357 mono_runtime_capture_context (MonoDomain *domain, MonoError *error)
7359 MONO_REQ_GC_UNSAFE_MODE;
7361 RuntimeInvokeFunction runtime_invoke;
7365 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
7366 MonoMethod *method = mono_get_context_capture_method ();
7367 MonoMethod *wrapper;
7370 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
7371 domain->capture_context_runtime_invoke = mono_compile_method_checked (wrapper, error);
7372 return_val_if_nok (error, NULL);
7373 domain->capture_context_method = mono_compile_method_checked (method, error);
7374 return_val_if_nok (error, NULL);
7377 runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
7379 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
7382 * mono_async_result_new:
7383 * \param domain domain where the object will be created.
7384 * \param handle wait handle.
7385 * \param state state to pass to AsyncResult
7386 * \param data C closure data.
7387 * \param error set on error.
7388 * Creates a new MonoAsyncResult (\c AsyncResult C# class) in the given domain.
7389 * If the handle is not null, the handle is initialized to a \c MonoWaitHandle.
7390 * On failure returns NULL and sets \p error.
7393 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data, MonoError *error)
7395 MONO_REQ_GC_UNSAFE_MODE;
7398 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, error);
7399 return_val_if_nok (error, NULL);
7400 MonoObject *context = mono_runtime_capture_context (domain, error);
7401 return_val_if_nok (error, NULL);
7402 /* we must capture the execution context from the original thread */
7404 MONO_OBJECT_SETREF (res, execution_context, context);
7405 /* note: result may be null if the flow is suppressed */
7408 res->data = (void **)data;
7409 MONO_OBJECT_SETREF (res, object_data, object_data);
7410 MONO_OBJECT_SETREF (res, async_state, state);
7411 MonoWaitHandle *wait_handle = mono_wait_handle_new (domain, handle, error);
7412 return_val_if_nok (error, NULL);
7414 MONO_OBJECT_SETREF (res, handle, (MonoObject *) wait_handle);
7416 res->sync_completed = FALSE;
7417 res->completed = FALSE;
7423 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
7425 MONO_REQ_GC_UNSAFE_MODE;
7432 g_assert (ares->async_delegate);
7434 ac = (MonoAsyncCall*) ares->object_data;
7436 res = mono_runtime_delegate_invoke_checked (ares->async_delegate, (void**) &ares->async_state, &error);
7437 if (mono_error_set_pending_exception (&error))
7440 gpointer wait_event = NULL;
7442 ac->msg->exc = NULL;
7444 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args, &error);
7446 /* The exit side of the invoke must not be aborted as it would leave the runtime in an undefined state */
7447 mono_threads_begin_abort_protected_block ();
7449 if (!ac->msg->exc) {
7450 MonoException *ex = mono_error_convert_to_exception (&error);
7451 ac->msg->exc = (MonoObject *)ex;
7453 mono_error_cleanup (&error);
7456 MONO_OBJECT_SETREF (ac, res, res);
7458 mono_monitor_enter ((MonoObject*) ares);
7459 ares->completed = 1;
7461 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
7462 mono_monitor_exit ((MonoObject*) ares);
7464 if (wait_event != NULL)
7465 mono_w32event_set (wait_event);
7467 error_init (&error); //the else branch would leave it in an undefined state
7469 mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
7471 mono_threads_end_abort_protected_block ();
7473 if (mono_error_set_pending_exception (&error))
7481 mono_message_init (MonoDomain *domain,
7482 MonoMethodMessage *this_obj,
7483 MonoReflectionMethod *method,
7484 MonoArray *out_args,
7487 MONO_REQ_GC_UNSAFE_MODE;
7489 static MonoMethod *init_message_method = NULL;
7491 if (!init_message_method) {
7492 init_message_method = mono_class_get_method_from_name (mono_defaults.mono_method_message_class, "InitMessage", 2);
7493 g_assert (init_message_method != NULL);
7497 /* FIXME set domain instead? */
7498 g_assert (domain == mono_domain_get ());
7505 mono_runtime_invoke_checked (init_message_method, this_obj, args, error);
7506 return is_ok (error);
7509 #ifndef DISABLE_REMOTING
7511 * mono_remoting_invoke:
7512 * \param real_proxy pointer to a \c RealProxy object
7513 * \param msg The \c MonoMethodMessage to execute
7514 * \param exc used to store exceptions
7515 * \param out_args used to store output arguments
7516 * This is used to call \c RealProxy::Invoke(). \c RealProxy::Invoke() returns an
7517 * \c IMessage interface and it is not trivial to extract results from there. So
7518 * we call an helper method \c PrivateInvoke instead of calling
7519 * \c RealProxy::Invoke() directly.
7520 * \returns the result object.
7523 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, MonoObject **exc, MonoArray **out_args, MonoError *error)
7525 MONO_REQ_GC_UNSAFE_MODE;
7528 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
7535 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
7538 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
7540 mono_error_set_not_supported (error, "Linked away.");
7543 real_proxy->vtable->domain->private_invoke_method = im;
7546 pa [0] = real_proxy;
7551 o = mono_runtime_try_invoke (im, NULL, pa, exc, error);
7552 return_val_if_nok (error, NULL);
7559 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
7560 MonoObject **exc, MonoArray **out_args, MonoError *error)
7562 MONO_REQ_GC_UNSAFE_MODE;
7564 static MonoClass *object_array_klass;
7569 MonoMethodSignature *sig;
7571 int i, j, outarg_count = 0;
7573 #ifndef DISABLE_REMOTING
7574 if (target && mono_object_is_transparent_proxy (target)) {
7575 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
7576 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7577 target = tp->rp->unwrapped_server;
7579 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args, error);
7584 domain = mono_domain_get ();
7585 method = msg->method->method;
7586 sig = mono_method_signature (method);
7588 for (i = 0; i < sig->param_count; i++) {
7589 if (sig->params [i]->byref)
7593 if (!object_array_klass) {
7596 klass = mono_array_class_get (mono_defaults.object_class, 1);
7599 mono_memory_barrier ();
7600 object_array_klass = klass;
7603 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, error);
7604 return_val_if_nok (error, NULL);
7606 mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
7609 MonoObject *ret = mono_runtime_try_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc, error);
7610 return_val_if_nok (error, NULL);
7612 for (i = 0, j = 0; i < sig->param_count; i++) {
7613 if (sig->params [i]->byref) {
7615 arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
7616 mono_array_setref (*out_args, j, arg);
7625 * prepare_to_string_method:
7627 * @target: Set to @obj or unboxed value if a valuetype
7629 * Returns: the ToString override for @obj. If @obj is a valuetype, @target is unboxed otherwise it's @obj.
7632 prepare_to_string_method (MonoObject *obj, void **target)
7634 MONO_REQ_GC_UNSAFE_MODE;
7636 static MonoMethod *to_string = NULL;
7644 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
7646 method = mono_object_get_virtual_method (obj, to_string);
7648 // Unbox value type if needed
7649 if (mono_class_is_valuetype (mono_method_get_class (method))) {
7650 *target = mono_object_unbox (obj);
7656 * mono_object_to_string:
7657 * \param obj The object
7658 * \param exc Any exception thrown by \c ToString. May be NULL.
7659 * \returns the result of calling \c ToString on an object.
7662 mono_object_to_string (MonoObject *obj, MonoObject **exc)
7665 MonoString *s = NULL;
7667 MonoMethod *method = prepare_to_string_method (obj, &target);
7669 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
7670 if (*exc == NULL && !mono_error_ok (&error))
7671 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
7673 mono_error_cleanup (&error);
7675 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
7676 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
7683 * mono_object_to_string_checked:
7684 * \param obj The object
7685 * \param error Set on error.
7686 * \returns the result of calling \c ToString() on an object. If the
7687 * method cannot be invoked or if it raises an exception, sets \p error
7691 mono_object_to_string_checked (MonoObject *obj, MonoError *error)
7695 MonoMethod *method = prepare_to_string_method (obj, &target);
7696 return (MonoString*) mono_runtime_invoke_checked (method, target, NULL, error);
7700 * mono_object_try_to_string:
7701 * \param obj The object
7702 * \param exc Any exception thrown by \c ToString(). Must not be NULL.
7703 * \param error Set if method cannot be invoked.
7704 * \returns the result of calling \c ToString() on an object. If the
7705 * method cannot be invoked sets \p error, if it raises an exception sets \p exc,
7709 mono_object_try_to_string (MonoObject *obj, MonoObject **exc, MonoError *error)
7714 MonoMethod *method = prepare_to_string_method (obj, &target);
7715 return (MonoString*) mono_runtime_try_invoke (method, target, NULL, exc, error);
7721 get_native_backtrace (MonoException *exc_raw)
7723 HANDLE_FUNCTION_ENTER ();
7724 MONO_HANDLE_DCL(MonoException, exc);
7725 char * trace = mono_exception_handle_get_native_backtrace (exc);
7726 HANDLE_FUNCTION_RETURN_VAL (trace);
7730 * mono_print_unhandled_exception:
7731 * \param exc The exception
7732 * Prints the unhandled exception.
7735 mono_print_unhandled_exception (MonoObject *exc)
7737 MONO_REQ_GC_UNSAFE_MODE;
7740 char *message = (char*)"";
7741 gboolean free_message = FALSE;
7744 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
7745 message = g_strdup ("OutOfMemoryException");
7746 free_message = TRUE;
7747 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
7748 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
7749 free_message = TRUE;
7752 if (((MonoException*)exc)->native_trace_ips) {
7753 message = get_native_backtrace ((MonoException*)exc);
7754 free_message = TRUE;
7756 MonoObject *other_exc = NULL;
7757 str = mono_object_try_to_string (exc, &other_exc, &error);
7758 if (other_exc == NULL && !is_ok (&error))
7759 other_exc = (MonoObject*)mono_error_convert_to_exception (&error);
7761 mono_error_cleanup (&error);
7763 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
7764 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
7766 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
7767 original_backtrace, nested_backtrace);
7769 g_free (original_backtrace);
7770 g_free (nested_backtrace);
7771 free_message = TRUE;
7773 message = mono_string_to_utf8_checked (str, &error);
7774 if (!mono_error_ok (&error)) {
7775 mono_error_cleanup (&error);
7776 message = (char *) "";
7778 free_message = TRUE;
7785 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
7786 * exc->vtable->klass->name, message);
7788 g_printerr ("\nUnhandled Exception:\n%s\n", message);
7795 * mono_delegate_ctor_with_method:
7796 * \param this pointer to an uninitialized delegate object
7797 * \param target target object
7798 * \param addr pointer to native code
7799 * \param method method
7800 * \param error set on error.
7801 * Initialize a delegate and sets a specific method, not the one
7802 * associated with \p addr. This is useful when sharing generic code.
7803 * In that case \p addr will most probably not be associated with the
7804 * correct instantiation of the method.
7805 * On failure returns FALSE and sets \p error.
7808 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method, MonoError *error)
7810 MONO_REQ_GC_UNSAFE_MODE;
7813 MonoDelegate *delegate = (MonoDelegate *)this_obj;
7815 g_assert (this_obj);
7818 g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
7821 delegate->method = method;
7823 mono_stats.delegate_creations++;
7825 #ifndef DISABLE_REMOTING
7826 if (target && mono_object_is_transparent_proxy (target)) {
7828 method = mono_marshal_get_remoting_invoke (method);
7829 #ifdef ENABLE_INTERPRETER
7830 g_error ("need RuntimeMethod in method_ptr when using interpreter");
7832 delegate->method_ptr = mono_compile_method_checked (method, error);
7833 return_val_if_nok (error, FALSE);
7834 MONO_OBJECT_SETREF (delegate, target, target);
7838 delegate->method_ptr = addr;
7839 MONO_OBJECT_SETREF (delegate, target, target);
7842 delegate->invoke_impl = callbacks.create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
7843 if (callbacks.init_delegate)
7844 callbacks.init_delegate (delegate);
7849 * mono_delegate_ctor:
7850 * \param this pointer to an uninitialized delegate object
7851 * \param target target object
7852 * \param addr pointer to native code
7853 * \param error set on error.
7854 * This is used to initialize a delegate.
7855 * On failure returns FALSE and sets \p error.
7858 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoError *error)
7860 MONO_REQ_GC_UNSAFE_MODE;
7863 MonoDomain *domain = mono_domain_get ();
7865 MonoMethod *method = NULL;
7869 ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
7871 if (!ji && domain != mono_get_root_domain ())
7872 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
7874 method = mono_jit_info_get_method (ji);
7875 g_assert (!mono_class_is_gtd (method->klass));
7878 return mono_delegate_ctor_with_method (this_obj, target, addr, method, error);
7882 * mono_method_call_message_new:
7883 * \param method method to encapsulate
7884 * \param params parameters to the method
7885 * \param invoke optional, delegate invoke.
7886 * \param cb async callback delegate.
7887 * \param state state passed to the async callback.
7888 * \param error set on error.
7889 * Translates arguments pointers into a \c MonoMethodMessage.
7890 * On failure returns NULL and sets \p error.
7893 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
7894 MonoDelegate **cb, MonoObject **state, MonoError *error)
7896 MONO_REQ_GC_UNSAFE_MODE;
7900 MonoDomain *domain = mono_domain_get ();
7901 MonoMethodSignature *sig = mono_method_signature (method);
7902 MonoMethodMessage *msg;
7905 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
7906 return_val_if_nok (error, NULL);
7909 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, error);
7910 return_val_if_nok (error, NULL);
7911 mono_message_init (domain, msg, rm, NULL, error);
7912 return_val_if_nok (error, NULL);
7913 count = sig->param_count - 2;
7915 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
7916 return_val_if_nok (error, NULL);
7917 mono_message_init (domain, msg, rm, NULL, error);
7918 return_val_if_nok (error, NULL);
7919 count = sig->param_count;
7922 for (i = 0; i < count; i++) {
7927 if (sig->params [i]->byref)
7928 vpos = *((gpointer *)params [i]);
7932 klass = mono_class_from_mono_type (sig->params [i]);
7934 if (klass->valuetype) {
7935 arg = mono_value_box_checked (domain, klass, vpos, error);
7936 return_val_if_nok (error, NULL);
7938 arg = *((MonoObject **)vpos);
7940 mono_array_setref (msg->args, i, arg);
7943 if (cb != NULL && state != NULL) {
7944 *cb = *((MonoDelegate **)params [i]);
7946 *state = *((MonoObject **)params [i]);
7953 * mono_method_return_message_restore:
7955 * Restore results from message based processing back to arguments pointers
7958 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args, MonoError *error)
7960 MONO_REQ_GC_UNSAFE_MODE;
7964 MonoMethodSignature *sig = mono_method_signature (method);
7965 int i, j, type, size, out_len;
7967 if (out_args == NULL)
7969 out_len = mono_array_length (out_args);
7973 for (i = 0, j = 0; i < sig->param_count; i++) {
7974 MonoType *pt = sig->params [i];
7979 mono_error_set_execution_engine (error, "The proxy call returned an incorrect number of output arguments");
7983 arg = (char *)mono_array_get (out_args, gpointer, j);
7986 g_assert (type != MONO_TYPE_VOID);
7988 if (MONO_TYPE_IS_REFERENCE (pt)) {
7989 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
7992 MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
7993 size = mono_class_value_size (klass, NULL);
7994 if (klass->has_references)
7995 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
7997 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
7999 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
8000 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
8009 #ifndef DISABLE_REMOTING
8012 * mono_load_remote_field:
8013 * \param this pointer to an object
8014 * \param klass klass of the object containing \p field
8015 * \param field the field to load
8016 * \param res a storage to store the result
8017 * This method is called by the runtime on attempts to load fields of
8018 * transparent proxy objects. \p this points to such TP, \p klass is the class of
8019 * the object containing \p field. \p res is a storage location which can be
8020 * used to store the result.
8021 * \returns an address pointing to the value of field.
8024 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
8027 gpointer result = mono_load_remote_field_checked (this_obj, klass, field, res, &error);
8028 mono_error_cleanup (&error);
8033 * mono_load_remote_field_checked:
8034 * \param this pointer to an object
8035 * \param klass klass of the object containing \p field
8036 * \param field the field to load
8037 * \param res a storage to store the result
8038 * \param error set on error
8039 * This method is called by the runtime on attempts to load fields of
8040 * transparent proxy objects. \p this points to such TP, \p klass is the class of
8041 * the object containing \p field. \p res is a storage location which can be
8042 * used to store the result.
8043 * \returns an address pointing to the value of field. On failure returns NULL and sets \p error.
8046 mono_load_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res, MonoError *error)
8048 MONO_REQ_GC_UNSAFE_MODE;
8050 static MonoMethod *getter = NULL;
8054 MonoDomain *domain = mono_domain_get ();
8055 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8056 MonoClass *field_class;
8057 MonoMethodMessage *msg;
8058 MonoArray *out_args;
8062 g_assert (mono_object_is_transparent_proxy (this_obj));
8063 g_assert (res != NULL);
8065 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8066 mono_field_get_value (tp->rp->unwrapped_server, field, res);
8071 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
8073 mono_error_set_not_supported (error, "Linked away.");
8078 field_class = mono_class_from_mono_type (field->type);
8080 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8081 return_val_if_nok (error, NULL);
8082 out_args = mono_array_new_checked (domain, mono_defaults.object_class, 1, error);
8083 return_val_if_nok (error, NULL);
8084 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, error);
8085 return_val_if_nok (error, NULL);
8086 mono_message_init (domain, msg, rm, out_args, error);
8087 return_val_if_nok (error, NULL);
8089 full_name = mono_type_get_full_name (klass);
8090 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
8091 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
8094 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8095 return_val_if_nok (error, NULL);
8098 mono_error_set_exception_instance (error, (MonoException *)exc);
8102 if (mono_array_length (out_args) == 0)
8105 mono_gc_wbarrier_generic_store (res, mono_array_get (out_args, MonoObject *, 0));
8107 if (field_class->valuetype) {
8108 return ((char *)*res) + sizeof (MonoObject);
8114 * mono_load_remote_field_new:
8118 * Missing documentation.
8121 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
8125 MonoObject *result = mono_load_remote_field_new_checked (this_obj, klass, field, &error);
8126 mono_error_cleanup (&error);
8131 * mono_load_remote_field_new_checked:
8132 * \param this pointer to an object
8133 * \param klass klass of the object containing \p field
8134 * \param field the field to load
8135 * \param error set on error.
8136 * This method is called by the runtime on attempts to load fields of
8137 * transparent proxy objects. \p this points to such TP, \p klass is the class of
8138 * the object containing \p field.
8139 * \returns a freshly allocated object containing the value of the field. On failure returns NULL and sets \p error.
8142 mono_load_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoError *error)
8144 MONO_REQ_GC_UNSAFE_MODE;
8148 static MonoMethod *tp_load = NULL;
8150 g_assert (mono_object_is_transparent_proxy (this_obj));
8153 tp_load = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "LoadRemoteFieldNew", -1);
8155 mono_error_set_not_supported (error, "Linked away.");
8160 /* MonoType *type = mono_class_get_type (klass); */
8166 return mono_runtime_invoke_checked (tp_load, this_obj, args, error);
8170 * mono_store_remote_field:
8171 * \param this_obj pointer to an object
8172 * \param klass klass of the object containing \p field
8173 * \param field the field to load
8174 * \param val the value/object to store
8175 * This method is called by the runtime on attempts to store fields of
8176 * transparent proxy objects. \p this_obj points to such TP, \p klass is the class of
8177 * the object containing \p field. \p val is the new value to store in \p field.
8180 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
8183 (void) mono_store_remote_field_checked (this_obj, klass, field, val, &error);
8184 mono_error_cleanup (&error);
8188 * mono_store_remote_field_checked:
8189 * \param this_obj pointer to an object
8190 * \param klass klass of the object containing \p field
8191 * \param field the field to load
8192 * \param val the value/object to store
8193 * \param error set on error
8194 * This method is called by the runtime on attempts to store fields of
8195 * transparent proxy objects. \p this_obj points to such TP, \p klass is the class of
8196 * the object containing \p field. \p val is the new value to store in \p field.
8197 * \returns on success returns TRUE, on failure returns FALSE and sets \p error.
8200 mono_store_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val, MonoError *error)
8203 MONO_REQ_GC_UNSAFE_MODE;
8207 MonoDomain *domain = mono_domain_get ();
8208 MonoClass *field_class;
8211 g_assert (mono_object_is_transparent_proxy (this_obj));
8213 field_class = mono_class_from_mono_type (field->type);
8215 if (field_class->valuetype) {
8216 arg = mono_value_box_checked (domain, field_class, val, error);
8217 return_val_if_nok (error, FALSE);
8219 arg = *((MonoObject**)val);
8222 return mono_store_remote_field_new_checked (this_obj, klass, field, arg, error);
8226 * mono_store_remote_field_new:
8231 * Missing documentation
8234 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
8237 (void) mono_store_remote_field_new_checked (this_obj, klass, field, arg, &error);
8238 mono_error_cleanup (&error);
8242 * mono_store_remote_field_new_checked:
8248 * Missing documentation
8251 mono_store_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg, MonoError *error)
8253 MONO_REQ_GC_UNSAFE_MODE;
8255 static MonoMethod *tp_store = NULL;
8259 g_assert (mono_object_is_transparent_proxy (this_obj));
8262 tp_store = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "StoreRemoteField", -1);
8264 mono_error_set_not_supported (error, "Linked away.");
8274 mono_runtime_invoke_checked (tp_store, this_obj, args, error);
8275 return is_ok (error);
8280 * mono_create_ftnptr:
8282 * Given a function address, create a function descriptor for it.
8283 * This is only needed on some platforms.
8286 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
8288 return callbacks.create_ftnptr (domain, addr);
8292 * mono_get_addr_from_ftnptr:
8294 * Given a pointer to a function descriptor, return the function address.
8295 * This is only needed on some platforms.
8298 mono_get_addr_from_ftnptr (gpointer descr)
8300 return callbacks.get_addr_from_ftnptr (descr);
8304 * mono_string_chars:
8305 * \param s a \c MonoString
8306 * \returns a pointer to the UTF-16 characters stored in the \c MonoString
8309 mono_string_chars (MonoString *s)
8311 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
8317 * mono_string_length:
8318 * \param s MonoString
8319 * \returns the length in characters of the string
8322 mono_string_length (MonoString *s)
8324 MONO_REQ_GC_UNSAFE_MODE;
8330 * mono_string_handle_length:
8331 * \param s \c MonoString
8332 * \returns the length in characters of the string
8335 mono_string_handle_length (MonoStringHandle s)
8337 MONO_REQ_GC_UNSAFE_MODE;
8339 return MONO_HANDLE_GETVAL (s, length);
8344 * mono_array_length:
8345 * \param array a \c MonoArray*
8346 * \returns the total number of elements in the array. This works for
8347 * both vectors and multidimensional arrays.
8350 mono_array_length (MonoArray *array)
8352 MONO_REQ_GC_UNSAFE_MODE;
8354 return array->max_length;
8358 * mono_array_addr_with_size:
8359 * \param array a \c MonoArray*
8360 * \param size size of the array elements
8361 * \param idx index into the array
8362 * Use this function to obtain the address for the \p idx item on the
8363 * \p array containing elements of size \p size.
8365 * This method performs no bounds checking or type checking.
8366 * \returns the address of the \p idx element in the array.
8369 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
8371 MONO_REQ_GC_UNSAFE_MODE;
8373 return ((char*)(array)->vector) + size * idx;
8378 mono_glist_to_array (GList *list, MonoClass *eclass, MonoError *error)
8380 MonoDomain *domain = mono_domain_get ();
8388 len = g_list_length (list);
8389 res = mono_array_new_checked (domain, eclass, len, error);
8390 return_val_if_nok (error, NULL);
8392 for (i = 0; list; list = list->next, i++)
8393 mono_array_set (res, gpointer, i, list->data);
8400 * The following section is purely to declare prototypes and
8401 * document the API, as these C files are processed by our
8407 * \param array array to alter
8408 * \param element_type A C type name, this macro will use the sizeof(type) to determine the element size
8409 * \param index index into the array
8410 * \param value value to set
8411 * Value Type version: This sets the \p index's element of the \p array
8412 * with elements of size sizeof(type) to the provided \p value.
8414 * This macro does not attempt to perform type checking or bounds checking.
8416 * Use this to set value types in a \c MonoArray.
8418 void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
8423 * mono_array_setref:
8424 * \param array array to alter
8425 * \param index index into the array
8426 * \param value value to set
8427 * Reference Type version. This sets the \p index's element of the
8428 * \p array with elements of size sizeof(type) to the provided \p value.
8430 * This macro does not attempt to perform type checking or bounds checking.
8432 * Use this to reference types in a \c MonoArray.
8434 void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
8440 * \param array array on which to operate on
8441 * \param element_type C element type (example: \c MonoString*, \c int, \c MonoObject*)
8442 * \param index index into the array
8444 * Use this macro to retrieve the \p index element of an \p array and
8445 * extract the value assuming that the elements of the array match
8446 * the provided type value.
8448 * This method can be used with both arrays holding value types and
8449 * reference types. For reference types, the \p type parameter should
8450 * be a \c MonoObject* or any subclass of it, like \c MonoString*.
8452 * This macro does not attempt to perform type checking or bounds checking.
8454 * \returns The element at the \p index position in the \p array.
8456 Type mono_array_get (MonoArray *array, Type element_type, uintptr_t index)