3 * Object creation for the Mono runtime
6 * Miguel de Icaza (miguel@ximian.com)
7 * Paolo Molaro (lupus@ximian.com)
9 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10 * Copyright 2004-2011 Novell, Inc (http://www.novell.com)
11 * Copyright 2001 Xamarin Inc (http://www.xamarin.com)
12 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
21 #include <mono/metadata/mono-endian.h>
22 #include <mono/metadata/tabledefs.h>
23 #include <mono/metadata/tokentype.h>
24 #include <mono/metadata/loader.h>
25 #include <mono/metadata/object.h>
26 #include <mono/metadata/gc-internals.h>
27 #include <mono/metadata/exception.h>
28 #include <mono/metadata/exception-internals.h>
29 #include <mono/metadata/domain-internals.h>
30 #include "mono/metadata/metadata-internals.h"
31 #include "mono/metadata/class-internals.h"
32 #include <mono/metadata/assembly.h>
33 #include <mono/metadata/marshal.h>
34 #include "mono/metadata/debug-helpers.h"
35 #include <mono/metadata/threads.h>
36 #include <mono/metadata/threads-types.h>
37 #include <mono/metadata/environment.h>
38 #include "mono/metadata/profiler-private.h"
39 #include "mono/metadata/security-manager.h"
40 #include <mono/metadata/verify-internals.h>
41 #include <mono/metadata/reflection-internals.h>
42 #include <mono/metadata/w32event.h>
43 #include <mono/utils/strenc.h>
44 #include <mono/utils/mono-counters.h>
45 #include <mono/utils/mono-error-internals.h>
46 #include <mono/utils/mono-memory-model.h>
47 #include <mono/utils/checked-build.h>
48 #include <mono/utils/mono-threads.h>
49 #include <mono/utils/mono-threads-coop.h>
50 #include "cominterop.h"
51 #include <mono/utils/w32api.h>
54 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error);
57 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error);
60 free_main_args (void);
63 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error);
66 array_full_copy_unchecked_size (MonoArray *src, MonoArray *dest, MonoClass *klass, uintptr_t size);
69 class_get_virtual_method (MonoClass *klass, MonoMethod *method, gboolean is_proxy, MonoError *error);
71 /* Class lazy loading functions */
72 static GENERATE_GET_CLASS_WITH_CACHE (pointer, "System.Reflection", "Pointer")
73 static GENERATE_GET_CLASS_WITH_CACHE (remoting_services, "System.Runtime.Remoting", "RemotingServices")
74 static GENERATE_GET_CLASS_WITH_CACHE (unhandled_exception_event_args, "System", "UnhandledExceptionEventArgs")
75 static GENERATE_GET_CLASS_WITH_CACHE (sta_thread_attribute, "System", "STAThreadAttribute")
76 static GENERATE_GET_CLASS_WITH_CACHE (activation_services, "System.Runtime.Remoting.Activation", "ActivationServices")
79 #define ldstr_lock() mono_os_mutex_lock (&ldstr_section)
80 #define ldstr_unlock() mono_os_mutex_unlock (&ldstr_section)
81 static mono_mutex_t ldstr_section;
85 * mono_runtime_object_init:
86 * \param this_obj the object to initialize
87 * This function calls the zero-argument constructor (which must
88 * exist) for the given object.
91 mono_runtime_object_init (MonoObject *this_obj)
94 mono_runtime_object_init_checked (this_obj, &error);
95 mono_error_assert_ok (&error);
99 * mono_runtime_object_init_checked:
100 * \param this_obj the object to initialize
101 * \param error set on error.
102 * This function calls the zero-argument constructor (which must
103 * exist) for the given object and returns TRUE on success, or FALSE
104 * on error and sets \p error.
107 mono_runtime_object_init_checked (MonoObject *this_obj, MonoError *error)
109 MONO_REQ_GC_UNSAFE_MODE;
111 MonoMethod *method = NULL;
112 MonoClass *klass = this_obj->vtable->klass;
115 method = mono_class_get_method_from_name (klass, ".ctor", 0);
117 g_error ("Could not lookup zero argument constructor for class %s", mono_type_get_full_name (klass));
119 if (method->klass->valuetype)
120 this_obj = (MonoObject *)mono_object_unbox (this_obj);
122 mono_runtime_invoke_checked (method, this_obj, NULL, error);
123 return is_ok (error);
126 /* The pseudo algorithm for type initialization from the spec
127 Note it doesn't say anything about domains - only threads.
129 2. If the type is initialized you are done.
130 2.1. If the type is not yet initialized, try to take an
132 2.2. If successful, record this thread as responsible for
133 initializing the type and proceed to step 2.3.
134 2.2.1. If not, see whether this thread or any thread
135 waiting for this thread to complete already holds the lock.
136 2.2.2. If so, return since blocking would create a deadlock. This thread
137 will now see an incompletely initialized state for the type,
138 but no deadlock will arise.
139 2.2.3 If not, block until the type is initialized then return.
140 2.3 Initialize the parent type and then all interfaces implemented
142 2.4 Execute the type initialization code for this type.
143 2.5 Mark the type as initialized, release the initialization lock,
144 awaken any threads waiting for this type to be initialized,
151 MonoNativeThreadId initializing_tid;
152 guint32 waiting_count;
155 /* condvar used to wait for 'done' becoming TRUE */
157 } TypeInitializationLock;
159 /* for locking access to type_initialization_hash and blocked_thread_hash */
160 static MonoCoopMutex type_initialization_section;
163 mono_type_initialization_lock (void)
165 /* The critical sections protected by this lock in mono_runtime_class_init_full () can block */
166 mono_coop_mutex_lock (&type_initialization_section);
170 mono_type_initialization_unlock (void)
172 mono_coop_mutex_unlock (&type_initialization_section);
176 mono_type_init_lock (TypeInitializationLock *lock)
178 MONO_REQ_GC_NEUTRAL_MODE;
180 mono_coop_mutex_lock (&lock->mutex);
184 mono_type_init_unlock (TypeInitializationLock *lock)
186 mono_coop_mutex_unlock (&lock->mutex);
189 /* from vtable to lock */
190 static GHashTable *type_initialization_hash;
192 /* from thread id to thread id being waited on */
193 static GHashTable *blocked_thread_hash;
196 static MonoThread *main_thread;
198 /* Functions supplied by the runtime */
199 static MonoRuntimeCallbacks callbacks;
202 * mono_thread_set_main:
203 * \param thread thread to set as the main thread
204 * This function can be used to instruct the runtime to treat \p thread
205 * as the main thread, ie, the thread that would normally execute the \c Main
206 * method. This basically means that at the end of \p thread, the runtime will
207 * wait for the existing foreground threads to quit and other such details.
210 mono_thread_set_main (MonoThread *thread)
212 MONO_REQ_GC_UNSAFE_MODE;
214 static gboolean registered = FALSE;
217 MONO_GC_REGISTER_ROOT_SINGLE (main_thread, MONO_ROOT_SOURCE_THREADING, "main thread object");
221 main_thread = thread;
225 * mono_thread_get_main:
228 mono_thread_get_main (void)
230 MONO_REQ_GC_UNSAFE_MODE;
236 mono_type_initialization_init (void)
238 mono_coop_mutex_init_recursive (&type_initialization_section);
239 type_initialization_hash = g_hash_table_new (NULL, NULL);
240 blocked_thread_hash = g_hash_table_new (NULL, NULL);
241 mono_os_mutex_init_recursive (&ldstr_section);
245 mono_type_initialization_cleanup (void)
248 /* This is causing race conditions with
249 * mono_release_type_locks
251 mono_coop_mutex_destroy (&type_initialization_section);
252 g_hash_table_destroy (type_initialization_hash);
253 type_initialization_hash = NULL;
255 mono_os_mutex_destroy (&ldstr_section);
256 g_hash_table_destroy (blocked_thread_hash);
257 blocked_thread_hash = NULL;
263 * get_type_init_exception_for_vtable:
265 * Return the stored type initialization exception for VTABLE.
267 static MonoException*
268 get_type_init_exception_for_vtable (MonoVTable *vtable)
270 MONO_REQ_GC_UNSAFE_MODE;
273 MonoDomain *domain = vtable->domain;
274 MonoClass *klass = vtable->klass;
278 if (!vtable->init_failed)
279 g_error ("Trying to get the init exception for a non-failed vtable of class %s", mono_type_get_full_name (klass));
282 * If the initializing thread was rudely aborted, the exception is not stored
286 mono_domain_lock (domain);
287 if (domain->type_init_exception_hash)
288 ex = (MonoException *)mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
289 mono_domain_unlock (domain);
292 if (klass->name_space && *klass->name_space)
293 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
295 full_name = g_strdup (klass->name);
296 ex = mono_get_exception_type_initialization_checked (full_name, NULL, &error);
298 return_val_if_nok (&error, NULL);
305 * mono_runtime_class_init:
306 * \param vtable vtable that needs to be initialized
307 * This routine calls the class constructor for \p vtable.
310 mono_runtime_class_init (MonoVTable *vtable)
312 MONO_REQ_GC_UNSAFE_MODE;
315 mono_runtime_class_init_full (vtable, &error);
316 mono_error_assert_ok (&error);
320 * Returns TRUE if the lock was freed.
321 * LOCKING: Caller should hold type_initialization_lock.
324 unref_type_lock (TypeInitializationLock *lock)
326 --lock->waiting_count;
327 if (lock->waiting_count == 0) {
328 mono_coop_mutex_destroy (&lock->mutex);
329 mono_coop_cond_destroy (&lock->cond);
338 * mono_runtime_class_init_full:
339 * \param vtable that neeeds to be initialized
340 * \param error set on error
341 * \returns TRUE if class constructor \c .cctor has been initialized successfully, or FALSE otherwise and sets \p error.
344 mono_runtime_class_init_full (MonoVTable *vtable, MonoError *error)
346 MONO_REQ_GC_UNSAFE_MODE;
348 MonoMethod *method = NULL;
351 MonoDomain *domain = vtable->domain;
352 TypeInitializationLock *lock;
353 MonoNativeThreadId tid;
354 int do_initialization = 0;
355 MonoDomain *last_domain = NULL;
356 gboolean pending_tae = FALSE;
360 if (vtable->initialized)
363 klass = vtable->klass;
365 if (!klass->image->checked_module_cctor) {
366 mono_image_check_for_module_cctor (klass->image);
367 if (klass->image->has_module_cctor) {
368 MonoClass *module_klass;
369 MonoVTable *module_vtable;
371 module_klass = mono_class_get_checked (klass->image, MONO_TOKEN_TYPE_DEF | 1, error);
376 module_vtable = mono_class_vtable_full (vtable->domain, module_klass, error);
379 if (!mono_runtime_class_init_full (module_vtable, error))
383 method = mono_class_get_cctor (klass);
385 vtable->initialized = 1;
389 tid = mono_native_thread_id_get ();
392 * Due some preprocessing inside a global lock. If we are the first thread
393 * trying to initialize this class, create a separate lock+cond var, and
394 * acquire it before leaving the global lock. The other threads will wait
398 mono_type_initialization_lock ();
399 /* double check... */
400 if (vtable->initialized) {
401 mono_type_initialization_unlock ();
404 if (vtable->init_failed) {
405 mono_type_initialization_unlock ();
407 /* The type initialization already failed once, rethrow the same exception */
408 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
411 lock = (TypeInitializationLock *)g_hash_table_lookup (type_initialization_hash, vtable);
413 /* This thread will get to do the initialization */
414 if (mono_domain_get () != domain) {
415 /* Transfer into the target domain */
416 last_domain = mono_domain_get ();
417 if (!mono_domain_set (domain, FALSE)) {
418 vtable->initialized = 1;
419 mono_type_initialization_unlock ();
420 mono_error_set_exception_instance (error, mono_get_exception_appdomain_unloaded ());
424 lock = (TypeInitializationLock *)g_malloc0 (sizeof (TypeInitializationLock));
425 mono_coop_mutex_init_recursive (&lock->mutex);
426 mono_coop_cond_init (&lock->cond);
427 lock->initializing_tid = tid;
428 lock->waiting_count = 1;
430 g_hash_table_insert (type_initialization_hash, vtable, lock);
431 do_initialization = 1;
434 TypeInitializationLock *pending_lock;
436 if (mono_native_thread_id_equals (lock->initializing_tid, tid)) {
437 mono_type_initialization_unlock ();
440 /* see if the thread doing the initialization is already blocked on this thread */
441 gboolean is_blocked = TRUE;
442 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (lock->initializing_tid));
443 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
444 if (mono_native_thread_id_equals (pending_lock->initializing_tid, tid)) {
445 if (!pending_lock->done) {
446 mono_type_initialization_unlock ();
449 /* the thread doing the initialization is blocked on this thread,
450 but on a lock that has already been freed. It just hasn't got
456 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (pending_lock->initializing_tid));
458 ++lock->waiting_count;
459 /* record the fact that we are waiting on the initializing thread */
461 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
463 mono_type_initialization_unlock ();
465 if (do_initialization) {
466 MonoException *exc = NULL;
468 /* We are holding the per-vtable lock, do the actual initialization */
470 mono_threads_begin_abort_protected_block ();
471 mono_runtime_try_invoke (method, NULL, NULL, (MonoObject**) &exc, error);
472 mono_threads_end_abort_protected_block ();
474 //exception extracted, error will be set to the right value later
475 if (exc == NULL && !mono_error_ok (error))//invoking failed but exc was not set
476 exc = mono_error_convert_to_exception (error);
478 mono_error_cleanup (error);
482 /* If the initialization failed, mark the class as unusable. */
483 /* Avoid infinite loops */
485 (klass->image == mono_defaults.corlib &&
486 !strcmp (klass->name_space, "System") &&
487 !strcmp (klass->name, "TypeInitializationException")))) {
488 vtable->init_failed = 1;
490 if (klass->name_space && *klass->name_space)
491 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
493 full_name = g_strdup (klass->name);
495 MonoException *exc_to_throw = mono_get_exception_type_initialization_checked (full_name, exc, error);
498 mono_error_assert_ok (error); //We can't recover from this, no way to fail a type we can't alloc a failure.
501 * Store the exception object so it could be thrown on subsequent
504 mono_domain_lock (domain);
505 if (!domain->type_init_exception_hash)
506 domain->type_init_exception_hash = mono_g_hash_table_new_type (mono_aligned_addr_hash, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_DOMAIN, "type initialization exceptions table");
507 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
508 mono_domain_unlock (domain);
512 mono_domain_set (last_domain, TRUE);
514 /* Signal to the other threads that we are done */
515 mono_type_init_lock (lock);
517 mono_coop_cond_broadcast (&lock->cond);
518 mono_type_init_unlock (lock);
521 * This can happen if the cctor self-aborts. We need to reactivate tae
522 * (next interruption checkpoint will throw it) and make sure we won't
523 * throw tie for the type.
525 if (exc && mono_object_class (exc) == mono_defaults.threadabortexception_class) {
527 mono_thread_resume_interruption (FALSE);
530 /* this just blocks until the initializing thread is done */
531 mono_type_init_lock (lock);
533 mono_coop_cond_wait (&lock->cond, &lock->mutex);
534 mono_type_init_unlock (lock);
537 /* Do cleanup and setting vtable->initialized inside the global lock again */
538 mono_type_initialization_lock ();
539 if (!do_initialization)
540 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
541 gboolean deleted = unref_type_lock (lock);
543 g_hash_table_remove (type_initialization_hash, vtable);
544 /* Have to set this here since we check it inside the global lock */
545 if (do_initialization && !vtable->init_failed)
546 vtable->initialized = 1;
547 mono_type_initialization_unlock ();
549 /* If vtable init fails because of TAE, we don't throw TIE, only the TAE */
550 if (vtable->init_failed && !pending_tae) {
551 /* Either we were the initializing thread or we waited for the initialization */
552 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
559 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
561 MONO_REQ_GC_NEUTRAL_MODE;
563 MonoVTable *vtable = (MonoVTable*)key;
565 TypeInitializationLock *lock = (TypeInitializationLock*) value;
566 if (mono_native_thread_id_equals (lock->initializing_tid, MONO_UINT_TO_NATIVE_THREAD_ID (GPOINTER_TO_UINT (user))) && !lock->done) {
569 * Have to set this since it cannot be set by the normal code in
570 * mono_runtime_class_init (). In this case, the exception object is not stored,
571 * and get_type_init_exception_for_class () needs to be aware of this.
573 mono_type_init_lock (lock);
574 vtable->init_failed = 1;
575 mono_coop_cond_broadcast (&lock->cond);
576 mono_type_init_unlock (lock);
577 gboolean deleted = unref_type_lock (lock);
585 mono_release_type_locks (MonoInternalThread *thread)
587 MONO_REQ_GC_UNSAFE_MODE;
589 mono_type_initialization_lock ();
590 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, GUINT_TO_POINTER (thread->tid));
591 mono_type_initialization_unlock ();
594 #ifndef DISABLE_REMOTING
597 create_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error)
599 if (!callbacks.create_remoting_trampoline)
600 g_error ("remoting not installed");
601 return callbacks.create_remoting_trampoline (domain, method, target, error);
606 static MonoImtTrampolineBuilder imt_trampoline_builder;
607 static gboolean always_build_imt_trampolines;
609 #if (MONO_IMT_SIZE > 32)
610 #error "MONO_IMT_SIZE cannot be larger than 32"
614 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
616 memcpy (&callbacks, cbs, sizeof (*cbs));
619 MonoRuntimeCallbacks*
620 mono_get_runtime_callbacks (void)
626 mono_install_imt_trampoline_builder (MonoImtTrampolineBuilder func)
628 imt_trampoline_builder = func;
632 mono_set_always_build_imt_trampolines (gboolean value)
634 always_build_imt_trampolines = value;
638 * mono_compile_method:
639 * \param method The method to compile.
640 * This JIT-compiles the method, and returns the pointer to the native code
644 mono_compile_method (MonoMethod *method)
647 gpointer result = mono_compile_method_checked (method, &error);
648 mono_error_cleanup (&error);
653 * mono_compile_method_checked:
654 * \param method The method to compile.
655 * \param error set on error.
656 * This JIT-compiles the method, and returns the pointer to the native code
657 * produced. On failure returns NULL and sets \p error.
660 mono_compile_method_checked (MonoMethod *method, MonoError *error)
664 MONO_REQ_GC_NEUTRAL_MODE
668 g_assert (callbacks.compile_method);
669 res = callbacks.compile_method (method, error);
674 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper, MonoError *error)
678 MONO_REQ_GC_NEUTRAL_MODE;
681 res = callbacks.create_jump_trampoline (domain, method, add_sync_wrapper, error);
686 mono_runtime_create_delegate_trampoline (MonoClass *klass)
688 MONO_REQ_GC_NEUTRAL_MODE
690 g_assert (callbacks.create_delegate_trampoline);
691 return callbacks.create_delegate_trampoline (mono_domain_get (), klass);
695 * mono_runtime_free_method:
696 * \param domain domain where the method is hosted
697 * \param method method to release
698 * This routine is invoked to free the resources associated with
699 * a method that has been JIT compiled. This is used to discard
700 * methods that were used only temporarily (for example, used in marshalling)
703 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
705 MONO_REQ_GC_NEUTRAL_MODE
707 if (callbacks.free_method)
708 callbacks.free_method (domain, method);
710 mono_method_clear_object (domain, method);
712 mono_free_method (method);
716 * The vtables in the root appdomain are assumed to be reachable by other
717 * roots, and we don't use typed allocation in the other domains.
720 /* The sync block is no longer a GC pointer */
721 #define GC_HEADER_BITMAP (0)
723 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
726 compute_class_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
728 MONO_REQ_GC_NEUTRAL_MODE;
730 MonoClassField *field;
736 max_size = mono_class_data_size (klass) / sizeof (gpointer);
738 max_size = klass->instance_size / sizeof (gpointer);
739 if (max_size > size) {
740 g_assert (offset <= 0);
741 bitmap = (gsize *)g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
746 /*An Ephemeron cannot be marked by sgen*/
747 if (!static_fields && klass->image == mono_defaults.corlib && !strcmp ("Ephemeron", klass->name)) {
749 memset (bitmap, 0, size / 8);
754 for (p = klass; p != NULL; p = p->parent) {
755 gpointer iter = NULL;
756 while ((field = mono_class_get_fields (p, &iter))) {
760 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
762 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
765 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
768 /* FIXME: should not happen, flag as type load error */
769 if (field->type->byref)
772 if (static_fields && field->offset == -1)
776 pos = field->offset / sizeof (gpointer);
779 type = mono_type_get_underlying_type (field->type);
780 switch (type->type) {
784 case MONO_TYPE_FNPTR:
786 case MONO_TYPE_STRING:
787 case MONO_TYPE_SZARRAY:
788 case MONO_TYPE_CLASS:
789 case MONO_TYPE_OBJECT:
790 case MONO_TYPE_ARRAY:
791 g_assert ((field->offset % sizeof(gpointer)) == 0);
793 g_assert (pos < size || pos <= max_size);
794 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
795 *max_set = MAX (*max_set, pos);
797 case MONO_TYPE_GENERICINST:
798 if (!mono_type_generic_inst_is_valuetype (type)) {
799 g_assert ((field->offset % sizeof(gpointer)) == 0);
801 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
802 *max_set = MAX (*max_set, pos);
807 case MONO_TYPE_VALUETYPE: {
808 MonoClass *fclass = mono_class_from_mono_type (field->type);
809 if (fclass->has_references) {
810 /* remove the object header */
811 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
825 case MONO_TYPE_BOOLEAN:
829 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
840 * mono_class_compute_bitmap:
842 * Mono internal function to compute a bitmap of reference fields in a class.
845 mono_class_compute_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
847 MONO_REQ_GC_NEUTRAL_MODE;
849 return compute_class_bitmap (klass, bitmap, size, offset, max_set, static_fields);
854 * similar to the above, but sets the bits in the bitmap for any non-ref field
855 * and ignores static fields
858 compute_class_non_ref_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset)
860 MonoClassField *field;
865 max_size = class->instance_size / sizeof (gpointer);
866 if (max_size >= size) {
867 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
870 for (p = class; p != NULL; p = p->parent) {
871 gpointer iter = NULL;
872 while ((field = mono_class_get_fields (p, &iter))) {
875 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
877 /* FIXME: should not happen, flag as type load error */
878 if (field->type->byref)
881 pos = field->offset / sizeof (gpointer);
884 type = mono_type_get_underlying_type (field->type);
885 switch (type->type) {
886 #if SIZEOF_VOID_P == 8
890 case MONO_TYPE_FNPTR:
895 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
896 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
897 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
900 #if SIZEOF_VOID_P == 4
904 case MONO_TYPE_FNPTR:
909 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
910 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
911 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
917 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
918 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
919 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
922 case MONO_TYPE_BOOLEAN:
925 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
927 case MONO_TYPE_STRING:
928 case MONO_TYPE_SZARRAY:
929 case MONO_TYPE_CLASS:
930 case MONO_TYPE_OBJECT:
931 case MONO_TYPE_ARRAY:
933 case MONO_TYPE_GENERICINST:
934 if (!mono_type_generic_inst_is_valuetype (type)) {
939 case MONO_TYPE_VALUETYPE: {
940 MonoClass *fclass = mono_class_from_mono_type (field->type);
941 /* remove the object header */
942 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
946 g_assert_not_reached ();
955 * mono_class_insecure_overlapping:
956 * check if a class with explicit layout has references and non-references
957 * fields overlapping.
959 * Returns: TRUE if it is insecure to load the type.
962 mono_class_insecure_overlapping (MonoClass *klass)
966 gsize default_bitmap [4] = {0};
968 gsize default_nrbitmap [4] = {0};
969 int i, insecure = FALSE;
972 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
973 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
975 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
976 int idx = i % (sizeof (bitmap [0]) * 8);
977 if (bitmap [idx] & nrbitmap [idx]) {
982 if (bitmap != default_bitmap)
984 if (nrbitmap != default_nrbitmap)
987 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
995 ves_icall_string_alloc (int length)
998 MonoString *str = mono_string_new_size_checked (mono_domain_get (), length, &error);
999 mono_error_set_pending_exception (&error);
1004 /* LOCKING: Acquires the loader lock */
1006 mono_class_compute_gc_descriptor (MonoClass *klass)
1008 MONO_REQ_GC_NEUTRAL_MODE;
1012 gsize default_bitmap [4] = {0};
1013 static gboolean gcj_inited = FALSE;
1014 MonoGCDescriptor gc_descr;
1017 mono_loader_lock ();
1019 mono_register_jit_icall (ves_icall_object_new_fast, "ves_icall_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
1020 mono_register_jit_icall (ves_icall_string_alloc, "ves_icall_string_alloc", mono_create_icall_signature ("object int"), FALSE);
1023 mono_loader_unlock ();
1027 mono_class_init (klass);
1029 if (klass->gc_descr_inited)
1032 bitmap = default_bitmap;
1033 if (klass == mono_defaults.string_class) {
1034 gc_descr = mono_gc_make_descr_for_string (bitmap, 2);
1035 } else if (klass->rank) {
1036 mono_class_compute_gc_descriptor (klass->element_class);
1037 if (MONO_TYPE_IS_REFERENCE (&klass->element_class->byval_arg)) {
1039 gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
1040 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1041 class->name_space, class->name);*/
1043 /* remove the object header */
1044 bitmap = compute_class_bitmap (klass->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
1045 gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, bitmap, mono_array_element_size (klass) / sizeof (gpointer), mono_array_element_size (klass));
1046 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1047 class->name_space, class->name);*/
1048 if (bitmap != default_bitmap)
1052 /*static int count = 0;
1055 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1056 gc_descr = mono_gc_make_descr_for_object (bitmap, max_set + 1, klass->instance_size);
1058 if (class->gc_descr == MONO_GC_DESCRIPTOR_NULL)
1059 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
1061 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
1062 if (bitmap != default_bitmap)
1066 /* Publish the data */
1067 mono_loader_lock ();
1068 klass->gc_descr = gc_descr;
1069 mono_memory_barrier ();
1070 klass->gc_descr_inited = TRUE;
1071 mono_loader_unlock ();
1075 * field_is_special_static:
1076 * @fklass: The MonoClass to look up.
1077 * @field: The MonoClassField describing the field.
1079 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1080 * SPECIAL_STATIC_NONE otherwise.
1083 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1085 MONO_REQ_GC_NEUTRAL_MODE;
1088 MonoCustomAttrInfo *ainfo;
1090 ainfo = mono_custom_attrs_from_field_checked (fklass, field, &error);
1091 mono_error_cleanup (&error); /* FIXME don't swallow the error? */
1094 for (i = 0; i < ainfo->num_attrs; ++i) {
1095 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1096 if (klass->image == mono_defaults.corlib) {
1097 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1098 mono_custom_attrs_free (ainfo);
1099 return SPECIAL_STATIC_THREAD;
1101 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1102 mono_custom_attrs_free (ainfo);
1103 return SPECIAL_STATIC_CONTEXT;
1107 mono_custom_attrs_free (ainfo);
1108 return SPECIAL_STATIC_NONE;
1111 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1112 #define mix(a,b,c) { \
1113 a -= c; a ^= rot(c, 4); c += b; \
1114 b -= a; b ^= rot(a, 6); a += c; \
1115 c -= b; c ^= rot(b, 8); b += a; \
1116 a -= c; a ^= rot(c,16); c += b; \
1117 b -= a; b ^= rot(a,19); a += c; \
1118 c -= b; c ^= rot(b, 4); b += a; \
1120 #define final(a,b,c) { \
1121 c ^= b; c -= rot(b,14); \
1122 a ^= c; a -= rot(c,11); \
1123 b ^= a; b -= rot(a,25); \
1124 c ^= b; c -= rot(b,16); \
1125 a ^= c; a -= rot(c,4); \
1126 b ^= a; b -= rot(a,14); \
1127 c ^= b; c -= rot(b,24); \
1131 * mono_method_get_imt_slot:
1133 * The IMT slot is embedded into AOTed code, so this must return the same value
1134 * for the same method across all executions. This means:
1135 * - pointers shouldn't be used as hash values.
1136 * - mono_metadata_str_hash () should be used for hashing strings.
1139 mono_method_get_imt_slot (MonoMethod *method)
1141 MONO_REQ_GC_NEUTRAL_MODE;
1143 MonoMethodSignature *sig;
1145 guint32 *hashes_start, *hashes;
1149 /* This can be used to stress tests the collision code */
1153 * We do this to simplify generic sharing. It will hurt
1154 * performance in cases where a class implements two different
1155 * instantiations of the same generic interface.
1156 * The code in build_imt_slots () depends on this.
1158 if (method->is_inflated)
1159 method = ((MonoMethodInflated*)method)->declaring;
1161 sig = mono_method_signature (method);
1162 hashes_count = sig->param_count + 4;
1163 hashes_start = (guint32 *)malloc (hashes_count * sizeof (guint32));
1164 hashes = hashes_start;
1166 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1167 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1168 method->klass->name_space, method->klass->name, method->name);
1171 /* Initialize hashes */
1172 hashes [0] = mono_metadata_str_hash (method->klass->name);
1173 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1174 hashes [2] = mono_metadata_str_hash (method->name);
1175 hashes [3] = mono_metadata_type_hash (sig->ret);
1176 for (i = 0; i < sig->param_count; i++) {
1177 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1180 /* Setup internal state */
1181 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1183 /* Handle most of the hashes */
1184 while (hashes_count > 3) {
1193 /* Handle the last 3 hashes (all the case statements fall through) */
1194 switch (hashes_count) {
1195 case 3 : c += hashes [2];
1196 case 2 : b += hashes [1];
1197 case 1 : a += hashes [0];
1199 case 0: /* nothing left to add */
1203 g_free (hashes_start);
1204 /* Report the result */
1205 return c % MONO_IMT_SIZE;
1214 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1215 MONO_REQ_GC_NEUTRAL_MODE;
1217 guint32 imt_slot = mono_method_get_imt_slot (method);
1218 MonoImtBuilderEntry *entry;
1220 if (slot_num >= 0 && imt_slot != slot_num) {
1221 /* we build just a single imt slot and this is not it */
1225 entry = (MonoImtBuilderEntry *)g_malloc0 (sizeof (MonoImtBuilderEntry));
1226 entry->key = method;
1227 entry->value.vtable_slot = vtable_slot;
1228 entry->next = imt_builder [imt_slot];
1229 if (imt_builder [imt_slot] != NULL) {
1230 entry->children = imt_builder [imt_slot]->children + 1;
1231 if (entry->children == 1) {
1232 mono_stats.imt_slots_with_collisions++;
1233 *imt_collisions_bitmap |= (1 << imt_slot);
1236 entry->children = 0;
1237 mono_stats.imt_used_slots++;
1239 imt_builder [imt_slot] = entry;
1242 char *method_name = mono_method_full_name (method, TRUE);
1243 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1244 method, method_name, imt_slot, vtable_slot, entry->children);
1245 g_free (method_name);
1252 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1254 MonoMethod *method = e->key;
1255 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1259 method->klass->name_space,
1260 method->klass->name,
1263 printf (" * %s: NULL\n", message);
1269 compare_imt_builder_entries (const void *p1, const void *p2) {
1270 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1271 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1273 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1277 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1279 MONO_REQ_GC_NEUTRAL_MODE;
1281 int count = end - start;
1282 int chunk_start = out_array->len;
1285 for (i = start; i < end; ++i) {
1286 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1287 item->key = sorted_array [i]->key;
1288 item->value = sorted_array [i]->value;
1289 item->has_target_code = sorted_array [i]->has_target_code;
1290 item->is_equals = TRUE;
1292 item->check_target_idx = out_array->len + 1;
1294 item->check_target_idx = 0;
1295 g_ptr_array_add (out_array, item);
1298 int middle = start + count / 2;
1299 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1301 item->key = sorted_array [middle]->key;
1302 item->is_equals = FALSE;
1303 g_ptr_array_add (out_array, item);
1304 imt_emit_ir (sorted_array, start, middle, out_array);
1305 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1311 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1312 MONO_REQ_GC_NEUTRAL_MODE;
1314 int number_of_entries = entries->children + 1;
1315 MonoImtBuilderEntry **sorted_array = (MonoImtBuilderEntry **)malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1316 GPtrArray *result = g_ptr_array_new ();
1317 MonoImtBuilderEntry *current_entry;
1320 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1321 sorted_array [i] = current_entry;
1323 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1325 /*for (i = 0; i < number_of_entries; i++) {
1326 print_imt_entry (" sorted array:", sorted_array [i], i);
1329 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1331 g_free (sorted_array);
1336 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1338 MONO_REQ_GC_NEUTRAL_MODE;
1340 if (imt_builder_entry != NULL) {
1341 if (imt_builder_entry->children == 0 && !fail_tramp && !always_build_imt_trampolines) {
1342 /* No collision, return the vtable slot contents */
1343 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1345 /* Collision, build the trampoline */
1346 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1349 result = imt_trampoline_builder (vtable, domain,
1350 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1351 for (i = 0; i < imt_ir->len; ++i)
1352 g_free (g_ptr_array_index (imt_ir, i));
1353 g_ptr_array_free (imt_ir, TRUE);
1365 static MonoImtBuilderEntry*
1366 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1369 * LOCKING: requires the loader and domain locks.
1373 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1375 MONO_REQ_GC_NEUTRAL_MODE;
1379 guint32 imt_collisions_bitmap = 0;
1380 MonoImtBuilderEntry **imt_builder = (MonoImtBuilderEntry **)calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1381 int method_count = 0;
1382 gboolean record_method_count_for_max_collisions = FALSE;
1383 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1386 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1388 for (i = 0; i < klass->interface_offsets_count; ++i) {
1389 MonoClass *iface = klass->interfaces_packed [i];
1390 int interface_offset = klass->interface_offsets_packed [i];
1391 int method_slot_in_interface, vt_slot;
1393 if (mono_class_has_variant_generic_params (iface))
1394 has_variant_iface = TRUE;
1396 mono_class_setup_methods (iface);
1397 vt_slot = interface_offset;
1398 int mcount = mono_class_get_method_count (iface);
1399 for (method_slot_in_interface = 0; method_slot_in_interface < mcount; method_slot_in_interface++) {
1402 if (slot_num >= 0 && mono_class_is_ginst (iface)) {
1404 * The imt slot of the method is the same as for its declaring method,
1405 * see the comment in mono_method_get_imt_slot (), so we can
1406 * avoid inflating methods which will be discarded by
1407 * add_imt_builder_entry anyway.
1409 method = mono_class_get_method_by_index (mono_class_get_generic_class (iface)->container_class, method_slot_in_interface);
1410 if (mono_method_get_imt_slot (method) != slot_num) {
1415 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1416 if (method->is_generic) {
1417 has_generic_virtual = TRUE;
1422 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1423 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1428 if (extra_interfaces) {
1429 int interface_offset = klass->vtable_size;
1431 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1432 MonoClass* iface = (MonoClass *)list_item->data;
1433 int method_slot_in_interface;
1434 int mcount = mono_class_get_method_count (iface);
1435 for (method_slot_in_interface = 0; method_slot_in_interface < mcount; method_slot_in_interface++) {
1436 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1438 if (method->is_generic)
1439 has_generic_virtual = TRUE;
1440 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1442 interface_offset += mcount;
1445 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1446 /* overwrite the imt slot only if we're building all the entries or if
1447 * we're building this specific one
1449 if (slot_num < 0 || i == slot_num) {
1450 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1453 if (imt_builder [i]) {
1454 MonoImtBuilderEntry *entry;
1456 /* Link entries with imt_builder [i] */
1457 for (entry = entries; entry->next; entry = entry->next) {
1459 MonoMethod *method = (MonoMethod*)entry->key;
1460 char *method_name = mono_method_full_name (method, TRUE);
1461 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1462 g_free (method_name);
1465 entry->next = imt_builder [i];
1466 entries->children += imt_builder [i]->children + 1;
1468 imt_builder [i] = entries;
1471 if (has_generic_virtual || has_variant_iface) {
1473 * There might be collisions later when the the trampoline is expanded.
1475 imt_collisions_bitmap |= (1 << i);
1478 * The IMT trampoline might be called with an instance of one of the
1479 * generic virtual methods, so has to fallback to the IMT trampoline.
1481 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline (vt, i));
1483 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1486 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1490 if (imt_builder [i] != NULL) {
1491 int methods_in_slot = imt_builder [i]->children + 1;
1492 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1493 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1494 record_method_count_for_max_collisions = TRUE;
1496 method_count += methods_in_slot;
1500 mono_stats.imt_number_of_methods += method_count;
1501 if (record_method_count_for_max_collisions) {
1502 mono_stats.imt_method_count_when_max_collisions = method_count;
1505 for (i = 0; i < MONO_IMT_SIZE; i++) {
1506 MonoImtBuilderEntry* entry = imt_builder [i];
1507 while (entry != NULL) {
1508 MonoImtBuilderEntry* next = entry->next;
1513 g_free (imt_builder);
1514 /* we OR the bitmap since we may build just a single imt slot at a time */
1515 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1519 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1520 MONO_REQ_GC_NEUTRAL_MODE;
1522 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1526 * mono_vtable_build_imt_slot:
1527 * \param vtable virtual object table struct
1528 * \param imt_slot slot in the IMT table
1529 * Fill the given \p imt_slot in the IMT table of \p vtable with
1530 * a trampoline or a trampoline for the case of collisions.
1531 * This is part of the internal mono API.
1532 * LOCKING: Take the domain lock.
1535 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1537 MONO_REQ_GC_NEUTRAL_MODE;
1539 gpointer *imt = (gpointer*)vtable;
1540 imt -= MONO_IMT_SIZE;
1541 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1543 /* no support for extra interfaces: the proxy objects will need
1544 * to build the complete IMT
1545 * Update and heck needs to ahppen inside the proper domain lock, as all
1546 * the changes made to a MonoVTable.
1548 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1549 mono_domain_lock (vtable->domain);
1550 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1551 if (!callbacks.imt_entry_inited (vtable, imt_slot))
1552 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1553 mono_domain_unlock (vtable->domain);
1554 mono_loader_unlock ();
1557 #define THUNK_THRESHOLD 10
1560 * mono_method_alloc_generic_virtual_trampoline:
1561 * \param domain a domain
1562 * \param size size in bytes
1563 * Allocs \p size bytes to be used for the code of a generic virtual
1564 * trampoline. It's either allocated from the domain's code manager or
1565 * reused from a previously invalidated piece.
1566 * LOCKING: The domain lock must be held.
1569 mono_method_alloc_generic_virtual_trampoline (MonoDomain *domain, int size)
1571 MONO_REQ_GC_NEUTRAL_MODE;
1573 static gboolean inited = FALSE;
1574 static int generic_virtual_trampolines_size = 0;
1577 mono_counters_register ("Generic virtual trampoline bytes",
1578 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_trampolines_size);
1581 generic_virtual_trampolines_size += size;
1583 return mono_domain_code_reserve (domain, size);
1586 typedef struct _GenericVirtualCase {
1590 struct _GenericVirtualCase *next;
1591 } GenericVirtualCase;
1594 * get_generic_virtual_entries:
1596 * Return IMT entries for the generic virtual method instances and
1597 * variant interface methods for vtable slot
1600 static MonoImtBuilderEntry*
1601 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1603 MONO_REQ_GC_NEUTRAL_MODE;
1605 GenericVirtualCase *list;
1606 MonoImtBuilderEntry *entries;
1608 mono_domain_lock (domain);
1609 if (!domain->generic_virtual_cases)
1610 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1612 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1615 for (; list; list = list->next) {
1616 MonoImtBuilderEntry *entry;
1618 if (list->count < THUNK_THRESHOLD)
1621 entry = g_new0 (MonoImtBuilderEntry, 1);
1622 entry->key = list->method;
1623 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1624 entry->has_target_code = 1;
1626 entry->children = entries->children + 1;
1627 entry->next = entries;
1631 mono_domain_unlock (domain);
1633 /* FIXME: Leaking memory ? */
1638 * \param domain a domain
1639 * \param vtable_slot pointer to the vtable slot
1640 * \param method the inflated generic virtual method
1641 * \param code the method's code
1643 * Registers a call via unmanaged code to a generic virtual method
1644 * instantiation or variant interface method. If the number of calls reaches a threshold
1645 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1646 * virtual method trampoline.
1649 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1650 gpointer *vtable_slot,
1651 MonoMethod *method, gpointer code)
1653 MONO_REQ_GC_NEUTRAL_MODE;
1655 static gboolean inited = FALSE;
1656 static int num_added = 0;
1657 static int num_freed = 0;
1659 GenericVirtualCase *gvc, *list;
1660 MonoImtBuilderEntry *entries;
1664 mono_domain_lock (domain);
1665 if (!domain->generic_virtual_cases)
1666 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1669 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1670 mono_counters_register ("Freed IMT trampolines", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_freed);
1674 /* Check whether the case was already added */
1675 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1678 if (gvc->method == method)
1683 /* If not found, make a new one */
1685 gvc = (GenericVirtualCase *)mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1686 gvc->method = method;
1689 gvc->next = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1691 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1696 if (++gvc->count == THUNK_THRESHOLD) {
1697 gpointer *old_thunk = (void **)*vtable_slot;
1698 gpointer vtable_trampoline = NULL;
1699 gpointer imt_trampoline = NULL;
1701 if ((gpointer)vtable_slot < (gpointer)vtable) {
1702 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1703 int imt_slot = MONO_IMT_SIZE + displacement;
1705 /* Force the rebuild of the trampoline at the next call */
1706 imt_trampoline = callbacks.get_imt_trampoline (vtable, imt_slot);
1707 *vtable_slot = imt_trampoline;
1709 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline (vtable, (gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1711 entries = get_generic_virtual_entries (domain, vtable_slot);
1713 sorted = imt_sort_slot_entries (entries);
1715 *vtable_slot = imt_trampoline_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1719 MonoImtBuilderEntry *next = entries->next;
1724 for (i = 0; i < sorted->len; ++i)
1725 g_free (g_ptr_array_index (sorted, i));
1726 g_ptr_array_free (sorted, TRUE);
1728 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1733 mono_domain_unlock (domain);
1736 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error);
1739 * mono_class_vtable:
1740 * \param domain the application domain
1741 * \param class the class to initialize
1742 * VTables are domain specific because we create domain specific code, and
1743 * they contain the domain specific static class data.
1744 * On failure, NULL is returned, and \c class->exception_type is set.
1747 mono_class_vtable (MonoDomain *domain, MonoClass *klass)
1750 MonoVTable* vtable = mono_class_vtable_full (domain, klass, &error);
1751 mono_error_cleanup (&error);
1756 * mono_class_vtable_full:
1757 * \param domain the application domain
1758 * \param class the class to initialize
1759 * \param error set on failure.
1760 * VTables are domain specific because we create domain specific code, and
1761 * they contain the domain specific static class data.
1764 mono_class_vtable_full (MonoDomain *domain, MonoClass *klass, MonoError *error)
1766 MONO_REQ_GC_UNSAFE_MODE;
1768 MonoClassRuntimeInfo *runtime_info;
1774 if (mono_class_has_failure (klass)) {
1775 mono_error_set_for_class_failure (error, klass);
1779 /* this check can be inlined in jitted code, too */
1780 runtime_info = klass->runtime_info;
1781 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1782 return runtime_info->domain_vtables [domain->domain_id];
1783 return mono_class_create_runtime_vtable (domain, klass, error);
1787 * mono_class_try_get_vtable:
1788 * \param domain the application domain
1789 * \param class the class to initialize
1790 * This function tries to get the associated vtable from \p class if
1791 * it was already created.
1794 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *klass)
1796 MONO_REQ_GC_NEUTRAL_MODE;
1798 MonoClassRuntimeInfo *runtime_info;
1802 runtime_info = klass->runtime_info;
1803 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1804 return runtime_info->domain_vtables [domain->domain_id];
1809 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1811 MONO_REQ_GC_NEUTRAL_MODE;
1813 size_t alloc_offset;
1816 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1817 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1818 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1820 if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1821 g_assert ((imt_table_bytes & 7) == 4);
1828 return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1832 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error)
1834 MONO_REQ_GC_UNSAFE_MODE;
1837 MonoClassRuntimeInfo *runtime_info, *old_info;
1838 MonoClassField *field;
1840 int i, vtable_slots;
1841 size_t imt_table_bytes;
1843 guint32 vtable_size, class_size;
1845 gpointer *interface_offsets;
1849 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1850 mono_domain_lock (domain);
1851 runtime_info = klass->runtime_info;
1852 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1853 mono_domain_unlock (domain);
1854 mono_loader_unlock ();
1855 return runtime_info->domain_vtables [domain->domain_id];
1857 if (!klass->inited || mono_class_has_failure (klass)) {
1858 if (!mono_class_init (klass) || mono_class_has_failure (klass)) {
1859 mono_domain_unlock (domain);
1860 mono_loader_unlock ();
1861 mono_error_set_for_class_failure (error, klass);
1866 /* Array types require that their element type be valid*/
1867 if (klass->byval_arg.type == MONO_TYPE_ARRAY || klass->byval_arg.type == MONO_TYPE_SZARRAY) {
1868 MonoClass *element_class = klass->element_class;
1869 if (!element_class->inited)
1870 mono_class_init (element_class);
1872 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1873 if (!mono_class_has_failure (element_class) && !element_class->vtable_size)
1874 mono_class_setup_vtable (element_class);
1876 if (mono_class_has_failure (element_class)) {
1877 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1878 if (!mono_class_has_failure (klass))
1879 mono_class_set_type_load_failure (klass, "");
1880 mono_domain_unlock (domain);
1881 mono_loader_unlock ();
1882 mono_error_set_for_class_failure (error, klass);
1888 * For some classes, mono_class_init () already computed klass->vtable_size, and
1889 * that is all that is needed because of the vtable trampolines.
1891 if (!klass->vtable_size)
1892 mono_class_setup_vtable (klass);
1894 if (mono_class_is_ginst (klass) && !klass->vtable)
1895 mono_class_check_vtable_constraints (klass, NULL);
1897 /* Initialize klass->has_finalize */
1898 mono_class_has_finalizer (klass);
1900 if (mono_class_has_failure (klass)) {
1901 mono_domain_unlock (domain);
1902 mono_loader_unlock ();
1903 mono_error_set_for_class_failure (error, klass);
1907 vtable_slots = klass->vtable_size;
1908 /* we add an additional vtable slot to store the pointer to static field data only when needed */
1909 class_size = mono_class_data_size (klass);
1913 if (klass->interface_offsets_count) {
1914 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1915 mono_stats.imt_number_of_tables++;
1916 mono_stats.imt_tables_size += imt_table_bytes;
1918 imt_table_bytes = 0;
1921 vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
1923 mono_stats.used_class_count++;
1924 mono_stats.class_vtable_size += vtable_size;
1926 interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
1927 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1928 g_assert (!((gsize)vt & 7));
1931 vt->rank = klass->rank;
1932 vt->domain = domain;
1934 mono_class_compute_gc_descriptor (klass);
1936 * We can't use typed allocation in the non-root domains, since the
1937 * collector needs the GC descriptor stored in the vtable even after
1938 * the mempool containing the vtable is destroyed when the domain is
1939 * unloaded. An alternative might be to allocate vtables in the GC
1940 * heap, but this does not seem to work (it leads to crashes inside
1941 * libgc). If that approach is tried, two gc descriptors need to be
1942 * allocated for each class: one for the root domain, and one for all
1943 * other domains. The second descriptor should contain a bit for the
1944 * vtable field in MonoObject, since we can no longer assume the
1945 * vtable is reachable by other roots after the appdomain is unloaded.
1947 #ifdef HAVE_BOEHM_GC
1948 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1949 vt->gc_descr = MONO_GC_DESCRIPTOR_NULL;
1952 vt->gc_descr = klass->gc_descr;
1954 gc_bits = mono_gc_get_vtable_bits (klass);
1955 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
1957 vt->gc_bits = gc_bits;
1960 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
1961 if (klass->has_static_refs) {
1962 MonoGCDescriptor statics_gc_descr;
1964 gsize default_bitmap [4] = {0};
1967 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1968 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], klass->name_space, klass->name, class_size);*/
1969 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1970 vt->vtable [klass->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr, MONO_ROOT_SOURCE_STATIC, "managed static variables");
1971 if (bitmap != default_bitmap)
1974 vt->vtable [klass->vtable_size] = mono_domain_alloc0 (domain, class_size);
1976 vt->has_static_fields = TRUE;
1977 mono_stats.class_static_data_size += class_size;
1981 while ((field = mono_class_get_fields (klass, &iter))) {
1982 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1984 if (mono_field_is_deleted (field))
1986 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1987 gint32 special_static = klass->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (klass, field);
1988 if (special_static != SPECIAL_STATIC_NONE) {
1989 guint32 size, offset;
1991 gsize default_bitmap [4] = {0};
1996 if (mono_type_is_reference (field->type)) {
1997 default_bitmap [0] = 1;
1999 bitmap = default_bitmap;
2000 } else if (mono_type_is_struct (field->type)) {
2001 fclass = mono_class_from_mono_type (field->type);
2002 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
2003 numbits = max_set + 1;
2005 default_bitmap [0] = 0;
2007 bitmap = default_bitmap;
2009 size = mono_type_size (field->type, &align);
2010 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
2011 if (!domain->special_static_fields)
2012 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2013 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2014 if (bitmap != default_bitmap)
2017 * This marks the field as special static to speed up the
2018 * checks in mono_field_static_get/set_value ().
2024 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2025 MonoClass *fklass = mono_class_from_mono_type (field->type);
2026 const char *data = mono_field_get_data (field);
2028 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2029 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2030 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2033 if (fklass->valuetype) {
2034 memcpy (t, data, mono_class_value_size (fklass, NULL));
2036 /* it's a pointer type: add check */
2037 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2044 vt->max_interface_id = klass->max_interface_id;
2045 vt->interface_bitmap = klass->interface_bitmap;
2047 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2048 // class->name, klass->interface_offsets_count);
2050 /* Initialize vtable */
2051 if (callbacks.get_vtable_trampoline) {
2052 // This also covers the AOT case
2053 for (i = 0; i < klass->vtable_size; ++i) {
2054 vt->vtable [i] = callbacks.get_vtable_trampoline (vt, i);
2057 mono_class_setup_vtable (klass);
2059 for (i = 0; i < klass->vtable_size; ++i) {
2062 cm = klass->vtable [i];
2064 vt->vtable [i] = callbacks.create_jit_trampoline (domain, cm, error);
2065 if (!is_ok (error)) {
2066 mono_domain_unlock (domain);
2067 mono_loader_unlock ();
2074 if (imt_table_bytes) {
2075 /* Now that the vtable is full, we can actually fill up the IMT */
2076 for (i = 0; i < MONO_IMT_SIZE; ++i)
2077 interface_offsets [i] = callbacks.get_imt_trampoline (vt, i);
2081 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2082 * re-acquire them and check if another thread has created the vtable in the meantime.
2084 /* Special case System.MonoType to avoid infinite recursion */
2085 if (klass != mono_defaults.runtimetype_class) {
2086 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2087 if (!is_ok (error)) {
2088 mono_domain_unlock (domain);
2089 mono_loader_unlock ();
2093 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2094 /* This is unregistered in
2095 unregister_vtable_reflection_type() in
2097 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2100 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (klass));
2102 /* class_vtable_array keeps an array of created vtables
2104 g_ptr_array_add (domain->class_vtable_array, vt);
2105 /* klass->runtime_info is protected by the loader lock, both when
2106 * it it enlarged and when it is stored info.
2110 * Store the vtable in klass->runtime_info.
2111 * klass->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2113 mono_memory_barrier ();
2115 old_info = klass->runtime_info;
2116 if (old_info && old_info->max_domain >= domain->domain_id) {
2117 /* someone already created a large enough runtime info */
2118 old_info->domain_vtables [domain->domain_id] = vt;
2120 int new_size = domain->domain_id;
2122 new_size = MAX (new_size, old_info->max_domain);
2124 /* make the new size a power of two */
2126 while (new_size > i)
2129 /* this is a bounded memory retention issue: may want to
2130 * handle it differently when we'll have a rcu-like system.
2132 runtime_info = (MonoClassRuntimeInfo *)mono_image_alloc0 (klass->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2133 runtime_info->max_domain = new_size - 1;
2134 /* copy the stuff from the older info */
2136 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2138 runtime_info->domain_vtables [domain->domain_id] = vt;
2140 mono_memory_barrier ();
2141 klass->runtime_info = runtime_info;
2144 if (klass == mono_defaults.runtimetype_class) {
2145 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2146 if (!is_ok (error)) {
2147 mono_domain_unlock (domain);
2148 mono_loader_unlock ();
2152 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2153 /* This is unregistered in
2154 unregister_vtable_reflection_type() in
2156 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2159 mono_domain_unlock (domain);
2160 mono_loader_unlock ();
2162 /* make sure the parent is initialized */
2163 /*FIXME shouldn't this fail the current type?*/
2165 mono_class_vtable_full (domain, klass->parent, error);
2170 #ifndef DISABLE_REMOTING
2172 * mono_class_proxy_vtable:
2173 * \param domain the application domain
2174 * \param remove_class the remote class
2175 * \param error set on error
2176 * Creates a vtable for transparent proxies. It is basically
2177 * a copy of the real vtable of the class wrapped in \p remote_class,
2178 * but all function pointers invoke the remoting functions, and
2179 * \c vtable->klass points to the transparent proxy class, and not to \p class.
2181 * On failure returns NULL and sets \p error
2184 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type, MonoError *error)
2186 MONO_REQ_GC_UNSAFE_MODE;
2188 MonoVTable *vt, *pvt;
2189 int i, j, vtsize, extra_interface_vtsize = 0;
2190 guint32 max_interface_id;
2192 GSList *extra_interfaces = NULL;
2193 MonoClass *klass = remote_class->proxy_class;
2194 gpointer *interface_offsets;
2195 uint8_t *bitmap = NULL;
2197 size_t imt_table_bytes;
2199 #ifdef COMPRESSED_INTERFACE_BITMAP
2205 vt = mono_class_vtable (domain, klass);
2206 g_assert (vt); /*FIXME property handle failure*/
2207 max_interface_id = vt->max_interface_id;
2209 /* Calculate vtable space for extra interfaces */
2210 for (j = 0; j < remote_class->interface_count; j++) {
2211 MonoClass* iclass = remote_class->interfaces[j];
2215 /*FIXME test for interfaces with variant generic arguments*/
2216 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, iclass->interface_id))
2217 continue; /* interface implemented by the class */
2218 if (g_slist_find (extra_interfaces, iclass))
2221 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2223 method_count = mono_class_num_methods (iclass);
2225 ifaces = mono_class_get_implemented_interfaces (iclass, error);
2229 for (i = 0; i < ifaces->len; ++i) {
2230 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2231 /*FIXME test for interfaces with variant generic arguments*/
2232 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, ic->interface_id))
2233 continue; /* interface implemented by the class */
2234 if (g_slist_find (extra_interfaces, ic))
2236 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2237 method_count += mono_class_num_methods (ic);
2239 g_ptr_array_free (ifaces, TRUE);
2243 extra_interface_vtsize += method_count * sizeof (gpointer);
2244 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2247 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2248 mono_stats.imt_number_of_tables++;
2249 mono_stats.imt_tables_size += imt_table_bytes;
2251 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer);
2253 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2255 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2256 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2257 g_assert (!((gsize)pvt & 7));
2259 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer));
2261 pvt->klass = mono_defaults.transparent_proxy_class;
2262 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2263 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2265 /* initialize vtable */
2266 mono_class_setup_vtable (klass);
2267 for (i = 0; i < klass->vtable_size; ++i) {
2270 if ((cm = klass->vtable [i])) {
2271 pvt->vtable [i] = create_remoting_trampoline (domain, cm, target_type, error);
2275 pvt->vtable [i] = NULL;
2278 if (mono_class_is_abstract (klass)) {
2279 /* create trampolines for abstract methods */
2280 for (k = klass; k; k = k->parent) {
2282 gpointer iter = NULL;
2283 while ((m = mono_class_get_methods (k, &iter)))
2284 if (!pvt->vtable [m->slot]) {
2285 pvt->vtable [m->slot] = create_remoting_trampoline (domain, m, target_type, error);
2292 pvt->max_interface_id = max_interface_id;
2293 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2294 #ifdef COMPRESSED_INTERFACE_BITMAP
2295 bitmap = (uint8_t *)g_malloc0 (bsize);
2297 bitmap = (uint8_t *)mono_domain_alloc0 (domain, bsize);
2300 for (i = 0; i < klass->interface_offsets_count; ++i) {
2301 int interface_id = klass->interfaces_packed [i]->interface_id;
2302 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2305 if (extra_interfaces) {
2306 int slot = klass->vtable_size;
2312 /* Create trampolines for the methods of the interfaces */
2313 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2314 interf = (MonoClass *)list_item->data;
2316 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2320 while ((cm = mono_class_get_methods (interf, &iter))) {
2321 pvt->vtable [slot + j++] = create_remoting_trampoline (domain, cm, target_type, error);
2326 slot += mono_class_num_methods (interf);
2330 /* Now that the vtable is full, we can actually fill up the IMT */
2331 build_imt (klass, pvt, domain, interface_offsets, extra_interfaces);
2332 if (extra_interfaces) {
2333 g_slist_free (extra_interfaces);
2336 #ifdef COMPRESSED_INTERFACE_BITMAP
2337 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2338 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2339 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2342 pvt->interface_bitmap = bitmap;
2346 if (extra_interfaces)
2347 g_slist_free (extra_interfaces);
2348 #ifdef COMPRESSED_INTERFACE_BITMAP
2354 #endif /* DISABLE_REMOTING */
2357 * mono_class_field_is_special_static:
2358 * \returns whether \p field is a thread/context static field.
2361 mono_class_field_is_special_static (MonoClassField *field)
2363 MONO_REQ_GC_NEUTRAL_MODE
2365 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2367 if (mono_field_is_deleted (field))
2369 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2370 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2377 * mono_class_field_get_special_static_type:
2378 * \param field The \c MonoClassField describing the field.
2379 * \returns \c SPECIAL_STATIC_THREAD if the field is thread static, \c SPECIAL_STATIC_CONTEXT if it is context static,
2380 * \c SPECIAL_STATIC_NONE otherwise.
2383 mono_class_field_get_special_static_type (MonoClassField *field)
2385 MONO_REQ_GC_NEUTRAL_MODE
2387 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2388 return SPECIAL_STATIC_NONE;
2389 if (mono_field_is_deleted (field))
2390 return SPECIAL_STATIC_NONE;
2391 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2392 return field_is_special_static (field->parent, field);
2393 return SPECIAL_STATIC_NONE;
2397 * mono_class_has_special_static_fields:
2398 * \returns whether \p klass has any thread/context static fields.
2401 mono_class_has_special_static_fields (MonoClass *klass)
2403 MONO_REQ_GC_NEUTRAL_MODE
2405 MonoClassField *field;
2409 while ((field = mono_class_get_fields (klass, &iter))) {
2410 g_assert (field->parent == klass);
2411 if (mono_class_field_is_special_static (field))
2418 #ifndef DISABLE_REMOTING
2420 * create_remote_class_key:
2421 * Creates an array of pointers that can be used as a hash key for a remote class.
2422 * The first element of the array is the number of pointers.
2425 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2427 MONO_REQ_GC_NEUTRAL_MODE;
2432 if (remote_class == NULL) {
2433 if (mono_class_is_interface (extra_class)) {
2434 key = (void **)g_malloc (sizeof(gpointer) * 3);
2435 key [0] = GINT_TO_POINTER (2);
2436 key [1] = mono_defaults.marshalbyrefobject_class;
2437 key [2] = extra_class;
2439 key = (void **)g_malloc (sizeof(gpointer) * 2);
2440 key [0] = GINT_TO_POINTER (1);
2441 key [1] = extra_class;
2444 if (extra_class != NULL && mono_class_is_interface (extra_class)) {
2445 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2446 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2447 key [1] = remote_class->proxy_class;
2449 // Keep the list of interfaces sorted
2450 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2451 if (extra_class && remote_class->interfaces [i] > extra_class) {
2452 key [j++] = extra_class;
2455 key [j] = remote_class->interfaces [i];
2458 key [j] = extra_class;
2460 // Replace the old class. The interface list is the same
2461 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2462 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2463 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2464 for (i = 0; i < remote_class->interface_count; i++)
2465 key [2 + i] = remote_class->interfaces [i];
2473 * copy_remote_class_key:
2475 * Make a copy of KEY in the domain and return the copy.
2478 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2480 MONO_REQ_GC_NEUTRAL_MODE
2482 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2483 gpointer *mp_key = (gpointer *)mono_domain_alloc (domain, key_size);
2485 memcpy (mp_key, key, key_size);
2491 * mono_remote_class:
2492 * \param domain the application domain
2493 * \param class_name name of the remote class
2494 * \param error set on error
2495 * Creates and initializes a \c MonoRemoteClass object for a remote type.
2496 * On failure returns NULL and sets \p error
2499 mono_remote_class (MonoDomain *domain, MonoStringHandle class_name, MonoClass *proxy_class, MonoError *error)
2501 MONO_REQ_GC_UNSAFE_MODE;
2503 MonoRemoteClass *rc;
2504 gpointer* key, *mp_key;
2509 key = create_remote_class_key (NULL, proxy_class);
2511 mono_domain_lock (domain);
2512 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2516 mono_domain_unlock (domain);
2520 name = mono_string_to_utf8_mp (domain->mp, MONO_HANDLE_RAW (class_name), error);
2521 if (!is_ok (error)) {
2523 mono_domain_unlock (domain);
2527 mp_key = copy_remote_class_key (domain, key);
2531 if (mono_class_is_interface (proxy_class)) {
2532 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2533 rc->interface_count = 1;
2534 rc->interfaces [0] = proxy_class;
2535 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2537 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2538 rc->interface_count = 0;
2539 rc->proxy_class = proxy_class;
2542 rc->default_vtable = NULL;
2543 rc->xdomain_vtable = NULL;
2544 rc->proxy_class_name = name;
2545 #ifndef DISABLE_PERFCOUNTERS
2546 mono_perfcounters->loader_bytes += mono_string_length (MONO_HANDLE_RAW (class_name)) + 1;
2549 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2551 mono_domain_unlock (domain);
2556 * clone_remote_class:
2557 * Creates a copy of the remote_class, adding the provided class or interface
2559 static MonoRemoteClass*
2560 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2562 MONO_REQ_GC_NEUTRAL_MODE;
2564 MonoRemoteClass *rc;
2565 gpointer* key, *mp_key;
2567 key = create_remote_class_key (remote_class, extra_class);
2568 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2574 mp_key = copy_remote_class_key (domain, key);
2578 if (mono_class_is_interface (extra_class)) {
2580 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2581 rc->proxy_class = remote_class->proxy_class;
2582 rc->interface_count = remote_class->interface_count + 1;
2584 // Keep the list of interfaces sorted, since the hash key of
2585 // the remote class depends on this
2586 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2587 if (remote_class->interfaces [i] > extra_class && i == j)
2588 rc->interfaces [j++] = extra_class;
2589 rc->interfaces [j] = remote_class->interfaces [i];
2592 rc->interfaces [j] = extra_class;
2594 // Replace the old class. The interface array is the same
2595 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2596 rc->proxy_class = extra_class;
2597 rc->interface_count = remote_class->interface_count;
2598 if (rc->interface_count > 0)
2599 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2602 rc->default_vtable = NULL;
2603 rc->xdomain_vtable = NULL;
2604 rc->proxy_class_name = remote_class->proxy_class_name;
2606 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2612 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxyHandle rp, MonoError *error)
2614 MONO_REQ_GC_UNSAFE_MODE;
2618 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2619 mono_domain_lock (domain);
2620 gint32 target_domain_id = MONO_HANDLE_GETVAL (rp, target_domain_id);
2621 if (target_domain_id != -1) {
2622 if (remote_class->xdomain_vtable == NULL)
2623 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN, error);
2624 mono_domain_unlock (domain);
2625 mono_loader_unlock ();
2626 return_val_if_nok (error, NULL);
2627 return remote_class->xdomain_vtable;
2629 if (remote_class->default_vtable == NULL) {
2630 MonoReflectionTypeHandle reftype = MONO_HANDLE_NEW (MonoReflectionType, NULL);
2631 MONO_HANDLE_GET (reftype, rp, class_to_proxy);
2633 MonoType *type = MONO_HANDLE_GETVAL (reftype, type);
2634 MonoClass *klass = mono_class_from_mono_type (type);
2636 if ((mono_class_is_com_object (klass) || (mono_class_get_com_object_class () && klass == mono_class_get_com_object_class ())) && !mono_vtable_is_remote (mono_class_vtable (mono_domain_get (), klass)))
2637 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP, error);
2640 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN, error);
2641 /* N.B. both branches of the if modify error */
2642 if (!is_ok (error)) {
2643 mono_domain_unlock (domain);
2644 mono_loader_unlock ();
2649 mono_domain_unlock (domain);
2650 mono_loader_unlock ();
2651 return remote_class->default_vtable;
2655 * mono_upgrade_remote_class:
2656 * \param domain the application domain
2657 * \param tproxy the proxy whose remote class has to be upgraded.
2658 * \param klass class to which the remote class can be casted.
2659 * \param error set on error
2660 * Updates the vtable of the remote class by adding the necessary method slots
2661 * and interface offsets so it can be safely casted to klass. klass can be a
2662 * class or an interface. On success returns TRUE, on failure returns FALSE and sets \p error.
2665 mono_upgrade_remote_class (MonoDomain *domain, MonoObjectHandle proxy_object, MonoClass *klass, MonoError *error)
2667 MONO_REQ_GC_UNSAFE_MODE;
2671 MonoTransparentProxyHandle tproxy = MONO_HANDLE_CAST (MonoTransparentProxy, proxy_object);
2672 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (tproxy, remote_class);
2674 gboolean redo_vtable;
2675 if (mono_class_is_interface (klass)) {
2678 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2679 if (remote_class->interfaces [i] == klass)
2680 redo_vtable = FALSE;
2683 redo_vtable = (remote_class->proxy_class != klass);
2686 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2687 mono_domain_lock (domain);
2689 MonoRemoteClass *fresh_remote_class = clone_remote_class (domain, remote_class, klass);
2690 MONO_HANDLE_SETVAL (tproxy, remote_class, MonoRemoteClass*, fresh_remote_class);
2691 MonoRealProxyHandle real_proxy = MONO_HANDLE_NEW (MonoRealProxy, NULL);
2692 MONO_HANDLE_GET (real_proxy, tproxy, rp);
2693 MONO_HANDLE_SETVAL (proxy_object, vtable, MonoVTable*, mono_remote_class_vtable (domain, fresh_remote_class, real_proxy, error));
2699 mono_domain_unlock (domain);
2700 mono_loader_unlock ();
2701 return is_ok (error);
2703 #endif /* DISABLE_REMOTING */
2707 * mono_object_get_virtual_method:
2708 * \param obj object to operate on.
2709 * \param method method
2710 * Retrieves the \c MonoMethod that would be called on \p obj if \p obj is passed as
2711 * the instance of a callvirt of \p method.
2714 mono_object_get_virtual_method (MonoObject *obj_raw, MonoMethod *method)
2716 MONO_REQ_GC_UNSAFE_MODE;
2717 HANDLE_FUNCTION_ENTER ();
2719 MONO_HANDLE_DCL (MonoObject, obj);
2720 MonoMethod *result = mono_object_handle_get_virtual_method (obj, method, &error);
2721 mono_error_assert_ok (&error);
2722 HANDLE_FUNCTION_RETURN_VAL (result);
2726 * mono_object_handle_get_virtual_method:
2727 * \param obj object to operate on.
2728 * \param method method
2729 * Retrieves the \c MonoMethod that would be called on \p obj if \p obj is passed as
2730 * the instance of a callvirt of \p method.
2733 mono_object_handle_get_virtual_method (MonoObjectHandle obj, MonoMethod *method, MonoError *error)
2737 gboolean is_proxy = FALSE;
2738 MonoClass *klass = mono_handle_class (obj);
2739 if (mono_class_is_transparent_proxy (klass)) {
2740 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), remote_class);
2741 klass = remote_class->proxy_class;
2744 return class_get_virtual_method (klass, method, is_proxy, error);
2748 class_get_virtual_method (MonoClass *klass, MonoMethod *method, gboolean is_proxy, MonoError *error)
2753 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2756 mono_class_setup_vtable (klass);
2757 MonoMethod **vtable = klass->vtable;
2759 if (method->slot == -1) {
2760 /* method->slot might not be set for instances of generic methods */
2761 if (method->is_inflated) {
2762 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2763 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2766 g_assert_not_reached ();
2770 MonoMethod *res = NULL;
2771 /* check method->slot is a valid index: perform isinstance? */
2772 if (method->slot != -1) {
2773 if (mono_class_is_interface (method->klass)) {
2775 gboolean variance_used = FALSE;
2776 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2777 g_assert (iface_offset > 0);
2778 res = vtable [iface_offset + method->slot];
2781 res = vtable [method->slot];
2785 #ifndef DISABLE_REMOTING
2787 /* It may be an interface, abstract class method or generic method */
2788 if (!res || mono_method_signature (res)->generic_param_count)
2791 /* generic methods demand invoke_with_check */
2792 if (mono_method_signature (res)->generic_param_count)
2793 res = mono_marshal_get_remoting_invoke_with_check (res);
2796 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2797 res = mono_cominterop_get_invoke (res);
2800 res = mono_marshal_get_remoting_invoke (res);
2805 if (method->is_inflated) {
2806 /* Have to inflate the result */
2807 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, error);
2815 do_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2817 MONO_REQ_GC_UNSAFE_MODE;
2819 MonoObject *result = NULL;
2821 g_assert (callbacks.runtime_invoke);
2825 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2826 mono_profiler_method_start_invoke (method);
2828 result = callbacks.runtime_invoke (method, obj, params, exc, error);
2830 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2831 mono_profiler_method_end_invoke (method);
2833 if (!mono_error_ok (error))
2840 * mono_runtime_invoke:
2841 * \param method method to invoke
2842 * \param obj object instance
2843 * \param params arguments to the method
2844 * \param exc exception information.
2845 * Invokes the method represented by \p method on the object \p obj.
2846 * \p obj is the \c this pointer, it should be NULL for static
2847 * methods, a \c MonoObject* for object instances and a pointer to
2848 * the value type for value types.
2850 * The params array contains the arguments to the method with the
2851 * same convention: \c MonoObject* pointers for object instances and
2852 * pointers to the value type otherwise.
2854 * From unmanaged code you'll usually use the
2855 * \c mono_runtime_invoke variant.
2857 * Note that this function doesn't handle virtual methods for
2858 * you, it will exec the exact method you pass: we still need to
2859 * expose a function to lookup the derived class implementation
2860 * of a virtual method (there are examples of this in the code,
2863 * You can pass NULL as the \p exc argument if you don't want to
2864 * catch exceptions, otherwise, \c *exc will be set to the exception
2865 * thrown, if any. if an exception is thrown, you can't use the
2866 * \c MonoObject* result from the function.
2868 * If the method returns a value type, it is boxed in an object
2872 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2877 res = mono_runtime_try_invoke (method, obj, params, exc, &error);
2878 if (*exc == NULL && !mono_error_ok(&error)) {
2879 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
2881 mono_error_cleanup (&error);
2883 res = mono_runtime_invoke_checked (method, obj, params, &error);
2884 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
2890 * mono_runtime_try_invoke:
2891 * \param method method to invoke
2892 * \param obj object instance
2893 * \param params arguments to the method
2894 * \param exc exception information.
2895 * \param error set on error
2896 * Invokes the method represented by \p method on the object \p obj.
2898 * \p obj is the \c this pointer, it should be NULL for static
2899 * methods, a \c MonoObject* for object instances and a pointer to
2900 * the value type for value types.
2902 * The params array contains the arguments to the method with the
2903 * same convention: \c MonoObject* pointers for object instances and
2904 * pointers to the value type otherwise.
2906 * From unmanaged code you'll usually use the
2907 * mono_runtime_invoke() variant.
2909 * Note that this function doesn't handle virtual methods for
2910 * you, it will exec the exact method you pass: we still need to
2911 * expose a function to lookup the derived class implementation
2912 * of a virtual method (there are examples of this in the code,
2915 * For this function, you must not pass NULL as the \p exc argument if
2916 * you don't want to catch exceptions, use
2917 * mono_runtime_invoke_checked(). If an exception is thrown, you
2918 * can't use the \c MonoObject* result from the function.
2920 * If this method cannot be invoked, \p error will be set and \p exc and
2921 * the return value must not be used.
2923 * If the method returns a value type, it is boxed in an object
2927 mono_runtime_try_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError* error)
2929 MONO_REQ_GC_UNSAFE_MODE;
2931 g_assert (exc != NULL);
2933 if (mono_runtime_get_no_exec ())
2934 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2936 return do_runtime_invoke (method, obj, params, exc, error);
2940 * mono_runtime_invoke_checked:
2941 * \param method method to invoke
2942 * \param obj object instance
2943 * \param params arguments to the method
2944 * \param error set on error
2945 * Invokes the method represented by \p method on the object \p obj.
2947 * \p obj is the \c this pointer, it should be NULL for static
2948 * methods, a \c MonoObject* for object instances and a pointer to
2949 * the value type for value types.
2951 * The \p params array contains the arguments to the method with the
2952 * same convention: \c MonoObject* pointers for object instances and
2953 * pointers to the value type otherwise.
2955 * From unmanaged code you'll usually use the
2956 * mono_runtime_invoke() variant.
2958 * Note that this function doesn't handle virtual methods for
2959 * you, it will exec the exact method you pass: we still need to
2960 * expose a function to lookup the derived class implementation
2961 * of a virtual method (there are examples of this in the code,
2964 * If an exception is thrown, you can't use the \c MonoObject* result
2965 * from the function.
2967 * If this method cannot be invoked, \p error will be set. If the
2968 * method throws an exception (and we're in coop mode) the exception
2969 * will be set in \p error.
2971 * If the method returns a value type, it is boxed in an object
2975 mono_runtime_invoke_checked (MonoMethod *method, void *obj, void **params, MonoError* error)
2977 MONO_REQ_GC_UNSAFE_MODE;
2979 if (mono_runtime_get_no_exec ())
2980 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2982 return do_runtime_invoke (method, obj, params, NULL, error);
2986 * mono_method_get_unmanaged_thunk:
2987 * \param method method to generate a thunk for.
2989 * Returns an \c unmanaged->managed thunk that can be used to call
2990 * a managed method directly from C.
2992 * The thunk's C signature closely matches the managed signature:
2994 * C#: <code>public bool Equals (object obj);</code>
2996 * C: <code>typedef MonoBoolean (*Equals)(MonoObject*, MonoObject*, MonoException**);</code>
2998 * The 1st (<code>this</code>) parameter must not be used with static methods:
3000 * C#: <code>public static bool ReferenceEquals (object a, object b);</code>
3002 * C: <code>typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*, MonoException**);</code>
3004 * The last argument must be a non-null \c MonoException* pointer.
3005 * It has "out" semantics. After invoking the thunk, \c *ex will be NULL if no
3006 * exception has been thrown in managed code. Otherwise it will point
3007 * to the \c MonoException* caught by the thunk. In this case, the result of
3008 * the thunk is undefined:
3011 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
3013 * MonoException *ex = NULL;
3015 * Equals func = mono_method_get_unmanaged_thunk (method);
3017 * MonoBoolean res = func (thisObj, objToCompare, &ex);
3021 * // handle exception
3026 * The calling convention of the thunk matches the platform's default
3027 * convention. This means that under Windows, C declarations must
3028 * contain the \c __stdcall attribute:
3030 * C: <code>typedef MonoBoolean (__stdcall *Equals)(MonoObject*, MonoObject*, MonoException**);</code>
3034 * Value type arguments and return values are treated as they were objects:
3036 * C#: <code>public static Rectangle Intersect (Rectangle a, Rectangle b);</code>
3037 * C: <code>typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);</code>
3039 * Arguments must be properly boxed upon trunk's invocation, while return
3040 * values must be unboxed.
3043 mono_method_get_unmanaged_thunk (MonoMethod *method)
3045 MONO_REQ_GC_NEUTRAL_MODE;
3046 MONO_REQ_API_ENTRYPOINT;
3051 g_assert (!mono_threads_is_coop_enabled ());
3053 MONO_ENTER_GC_UNSAFE;
3054 method = mono_marshal_get_thunk_invoke_wrapper (method);
3055 res = mono_compile_method_checked (method, &error);
3056 mono_error_cleanup (&error);
3057 MONO_EXIT_GC_UNSAFE;
3063 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
3065 MONO_REQ_GC_UNSAFE_MODE;
3069 /* object fields cannot be byref, so we don't need a
3071 gpointer *p = (gpointer*)dest;
3078 case MONO_TYPE_BOOLEAN:
3080 case MONO_TYPE_U1: {
3081 guint8 *p = (guint8*)dest;
3082 *p = value ? *(guint8*)value : 0;
3087 case MONO_TYPE_CHAR: {
3088 guint16 *p = (guint16*)dest;
3089 *p = value ? *(guint16*)value : 0;
3092 #if SIZEOF_VOID_P == 4
3097 case MONO_TYPE_U4: {
3098 gint32 *p = (gint32*)dest;
3099 *p = value ? *(gint32*)value : 0;
3102 #if SIZEOF_VOID_P == 8
3107 case MONO_TYPE_U8: {
3108 gint64 *p = (gint64*)dest;
3109 *p = value ? *(gint64*)value : 0;
3112 case MONO_TYPE_R4: {
3113 float *p = (float*)dest;
3114 *p = value ? *(float*)value : 0;
3117 case MONO_TYPE_R8: {
3118 double *p = (double*)dest;
3119 *p = value ? *(double*)value : 0;
3122 case MONO_TYPE_STRING:
3123 case MONO_TYPE_SZARRAY:
3124 case MONO_TYPE_CLASS:
3125 case MONO_TYPE_OBJECT:
3126 case MONO_TYPE_ARRAY:
3127 mono_gc_wbarrier_generic_store (dest, deref_pointer ? *(MonoObject **)value : (MonoObject *)value);
3129 case MONO_TYPE_FNPTR:
3130 case MONO_TYPE_PTR: {
3131 gpointer *p = (gpointer*)dest;
3132 *p = deref_pointer? *(gpointer*)value: value;
3135 case MONO_TYPE_VALUETYPE:
3136 /* note that 't' and 'type->type' can be different */
3137 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3138 t = mono_class_enum_basetype (type->data.klass)->type;
3141 MonoClass *klass = mono_class_from_mono_type (type);
3142 int size = mono_class_value_size (klass, NULL);
3144 mono_gc_bzero_atomic (dest, size);
3146 mono_gc_wbarrier_value_copy (dest, value, 1, klass);
3149 case MONO_TYPE_GENERICINST:
3150 t = type->data.generic_class->container_class->byval_arg.type;
3153 g_error ("got type %x", type->type);
3158 * mono_field_set_value:
3159 * \param obj Instance object
3160 * \param field \c MonoClassField describing the field to set
3161 * \param value The value to be set
3163 * Sets the value of the field described by \p field in the object instance \p obj
3164 * to the value passed in \p value. This method should only be used for instance
3165 * fields. For static fields, use \c mono_field_static_set_value.
3167 * The value must be in the native format of the field type.
3170 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3172 MONO_REQ_GC_UNSAFE_MODE;
3176 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3178 dest = (char*)obj + field->offset;
3179 mono_copy_value (field->type, dest, value, FALSE);
3183 * mono_field_static_set_value:
3184 * \param field \c MonoClassField describing the field to set
3185 * \param value The value to be set
3186 * Sets the value of the static field described by \p field
3187 * to the value passed in \p value.
3188 * The value must be in the native format of the field type.
3191 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3193 MONO_REQ_GC_UNSAFE_MODE;
3197 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3198 /* you cant set a constant! */
3199 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3201 if (field->offset == -1) {
3202 /* Special static */
3205 mono_domain_lock (vt->domain);
3206 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3207 mono_domain_unlock (vt->domain);
3208 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3210 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3212 mono_copy_value (field->type, dest, value, FALSE);
3216 * mono_vtable_get_static_field_data:
3218 * Internal use function: return a pointer to the memory holding the static fields
3219 * for a class or NULL if there are no static fields.
3220 * This is exported only for use by the debugger.
3223 mono_vtable_get_static_field_data (MonoVTable *vt)
3225 MONO_REQ_GC_NEUTRAL_MODE
3227 if (!vt->has_static_fields)
3229 return vt->vtable [vt->klass->vtable_size];
3233 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3235 MONO_REQ_GC_UNSAFE_MODE;
3239 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3240 if (field->offset == -1) {
3241 /* Special static */
3244 mono_domain_lock (vt->domain);
3245 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3246 mono_domain_unlock (vt->domain);
3247 src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3249 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3252 src = (guint8*)obj + field->offset;
3259 * mono_field_get_value:
3260 * \param obj Object instance
3261 * \param field \c MonoClassField describing the field to fetch information from
3262 * \param value pointer to the location where the value will be stored
3263 * Use this routine to get the value of the field \p field in the object
3266 * The pointer provided by value must be of the field type, for reference
3267 * types this is a \c MonoObject*, for value types its the actual pointer to
3275 * mono_field_get_value (obj, int_field, &i);
3279 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3281 MONO_REQ_GC_UNSAFE_MODE;
3287 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3289 src = (char*)obj + field->offset;
3290 mono_copy_value (field->type, value, src, TRUE);
3294 * mono_field_get_value_object:
3295 * \param domain domain where the object will be created (if boxing)
3296 * \param field \c MonoClassField describing the field to fetch information from
3297 * \param obj The object instance for the field.
3298 * \returns a new \c MonoObject with the value from the given field. If the
3299 * field represents a value type, the value is boxed.
3302 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3305 MonoObject* result = mono_field_get_value_object_checked (domain, field, obj, &error);
3306 mono_error_assert_ok (&error);
3311 * mono_field_get_value_object_checked:
3312 * \param domain domain where the object will be created (if boxing)
3313 * \param field \c MonoClassField describing the field to fetch information from
3314 * \param obj The object instance for the field.
3315 * \param error Set on error.
3316 * \returns a new \c MonoObject with the value from the given field. If the
3317 * field represents a value type, the value is boxed. On error returns NULL and sets \p error.
3320 mono_field_get_value_object_checked (MonoDomain *domain, MonoClassField *field, MonoObject *obj, MonoError *error)
3322 MONO_REQ_GC_UNSAFE_MODE;
3328 MonoVTable *vtable = NULL;
3330 gboolean is_static = FALSE;
3331 gboolean is_ref = FALSE;
3332 gboolean is_literal = FALSE;
3333 gboolean is_ptr = FALSE;
3334 MonoType *type = mono_field_get_type_checked (field, error);
3336 return_val_if_nok (error, NULL);
3338 switch (type->type) {
3339 case MONO_TYPE_STRING:
3340 case MONO_TYPE_OBJECT:
3341 case MONO_TYPE_CLASS:
3342 case MONO_TYPE_ARRAY:
3343 case MONO_TYPE_SZARRAY:
3348 case MONO_TYPE_BOOLEAN:
3351 case MONO_TYPE_CHAR:
3360 case MONO_TYPE_VALUETYPE:
3361 is_ref = type->byref;
3363 case MONO_TYPE_GENERICINST:
3364 is_ref = !mono_type_generic_inst_is_valuetype (type);
3370 g_error ("type 0x%x not handled in "
3371 "mono_field_get_value_object", type->type);
3375 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3378 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3382 vtable = mono_class_vtable_full (domain, field->parent, error);
3383 return_val_if_nok (error, NULL);
3385 if (!vtable->initialized) {
3386 mono_runtime_class_init_full (vtable, error);
3387 return_val_if_nok (error, NULL);
3396 get_default_field_value (domain, field, &o, error);
3397 return_val_if_nok (error, NULL);
3398 } else if (is_static) {
3399 mono_field_static_get_value_checked (vtable, field, &o, error);
3400 return_val_if_nok (error, NULL);
3402 mono_field_get_value (obj, field, &o);
3408 static MonoMethod *m;
3414 MonoClass *ptr_klass = mono_class_get_pointer_class ();
3415 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3421 get_default_field_value (domain, field, v, error);
3422 return_val_if_nok (error, NULL);
3423 } else if (is_static) {
3424 mono_field_static_get_value_checked (vtable, field, v, error);
3425 return_val_if_nok (error, NULL);
3427 mono_field_get_value (obj, field, v);
3430 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3431 args [0] = ptr ? *ptr : NULL;
3432 args [1] = mono_type_get_object_checked (mono_domain_get (), type, error);
3433 return_val_if_nok (error, NULL);
3435 o = mono_runtime_invoke_checked (m, NULL, args, error);
3436 return_val_if_nok (error, NULL);
3441 /* boxed value type */
3442 klass = mono_class_from_mono_type (type);
3444 if (mono_class_is_nullable (klass))
3445 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass, error);
3447 o = mono_object_new_checked (domain, klass, error);
3448 return_val_if_nok (error, NULL);
3449 v = ((gchar *) o) + sizeof (MonoObject);
3452 get_default_field_value (domain, field, v, error);
3453 return_val_if_nok (error, NULL);
3454 } else if (is_static) {
3455 mono_field_static_get_value_checked (vtable, field, v, error);
3456 return_val_if_nok (error, NULL);
3458 mono_field_get_value (obj, field, v);
3465 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value, MonoError *error)
3467 MONO_REQ_GC_UNSAFE_MODE;
3471 const char *p = blob;
3472 mono_metadata_decode_blob_size (p, &p);
3475 case MONO_TYPE_BOOLEAN:
3478 *(guint8 *) value = *p;
3480 case MONO_TYPE_CHAR:
3483 *(guint16*) value = read16 (p);
3487 *(guint32*) value = read32 (p);
3491 *(guint64*) value = read64 (p);
3494 readr4 (p, (float*) value);
3497 readr8 (p, (double*) value);
3499 case MONO_TYPE_STRING:
3500 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob, error);
3502 case MONO_TYPE_CLASS:
3503 *(gpointer*) value = NULL;
3507 g_warning ("type 0x%02x should not be in constant table", type);
3513 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error)
3515 MONO_REQ_GC_NEUTRAL_MODE;
3517 MonoTypeEnum def_type;
3522 data = mono_class_get_field_default_value (field, &def_type);
3523 mono_get_constant_value_from_blob (domain, def_type, data, value, error);
3527 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3529 MONO_REQ_GC_UNSAFE_MODE;
3535 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3537 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3538 get_default_field_value (vt->domain, field, value, error);
3542 if (field->offset == -1) {
3543 /* Special static */
3544 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3545 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3547 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3549 mono_copy_value (field->type, value, src, TRUE);
3553 * mono_field_static_get_value:
3554 * \param vt vtable to the object
3555 * \param field \c MonoClassField describing the field to fetch information from
3556 * \param value where the value is returned
3557 * Use this routine to get the value of the static field \p field value.
3559 * The pointer provided by value must be of the field type, for reference
3560 * types this is a \c MonoObject*, for value types its the actual pointer to
3568 * mono_field_static_get_value (vt, int_field, &i);
3572 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3574 MONO_REQ_GC_NEUTRAL_MODE;
3577 mono_field_static_get_value_checked (vt, field, value, &error);
3578 mono_error_cleanup (&error);
3582 * mono_field_static_get_value_checked:
3583 * \param vt vtable to the object
3584 * \param field \c MonoClassField describing the field to fetch information from
3585 * \param value where the value is returned
3586 * \param error set on error
3587 * Use this routine to get the value of the static field \p field value.
3589 * The pointer provided by value must be of the field type, for reference
3590 * types this is a \c MonoObject*, for value types its the actual pointer to
3595 * mono_field_static_get_value_checked (vt, int_field, &i, error);
3596 * if (!is_ok (error)) { ... }
3598 * On failure sets \p error.
3601 mono_field_static_get_value_checked (MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3603 MONO_REQ_GC_NEUTRAL_MODE;
3605 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value, error);
3609 * mono_property_set_value:
3610 * \param prop MonoProperty to set
3611 * \param obj instance object on which to act
3612 * \param params parameters to pass to the propery
3613 * \param exc optional exception
3614 * Invokes the property's set method with the given arguments on the
3615 * object instance obj (or NULL for static properties).
3617 * You can pass NULL as the exc argument if you don't want to
3618 * catch exceptions, otherwise, \c *exc will be set to the exception
3619 * thrown, if any. if an exception is thrown, you can't use the
3620 * \c MonoObject* result from the function.
3623 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3625 MONO_REQ_GC_UNSAFE_MODE;
3628 do_runtime_invoke (prop->set, obj, params, exc, &error);
3629 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3630 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3632 mono_error_cleanup (&error);
3637 * mono_property_set_value_checked:
3638 * \param prop \c MonoProperty to set
3639 * \param obj instance object on which to act
3640 * \param params parameters to pass to the propery
3641 * \param error set on error
3642 * Invokes the property's set method with the given arguments on the
3643 * object instance \p obj (or NULL for static properties).
3644 * \returns TRUE on success. On failure returns FALSE and sets \p error.
3645 * If an exception is thrown, it will be caught and returned via \p error.
3648 mono_property_set_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3650 MONO_REQ_GC_UNSAFE_MODE;
3655 do_runtime_invoke (prop->set, obj, params, &exc, error);
3656 if (exc != NULL && is_ok (error))
3657 mono_error_set_exception_instance (error, (MonoException*)exc);
3658 return is_ok (error);
3662 * mono_property_get_value:
3663 * \param prop \c MonoProperty to fetch
3664 * \param obj instance object on which to act
3665 * \param params parameters to pass to the propery
3666 * \param exc optional exception
3667 * Invokes the property's \c get method with the given arguments on the
3668 * object instance \p obj (or NULL for static properties).
3670 * You can pass NULL as the \p exc argument if you don't want to
3671 * catch exceptions, otherwise, \c *exc will be set to the exception
3672 * thrown, if any. if an exception is thrown, you can't use the
3673 * \c MonoObject* result from the function.
3675 * \returns the value from invoking the \c get method on the property.
3678 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3680 MONO_REQ_GC_UNSAFE_MODE;
3683 MonoObject *val = do_runtime_invoke (prop->get, obj, params, exc, &error);
3684 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3685 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3687 mono_error_cleanup (&error); /* FIXME don't raise here */
3694 * mono_property_get_value_checked:
3695 * \param prop \c MonoProperty to fetch
3696 * \param obj instance object on which to act
3697 * \param params parameters to pass to the propery
3698 * \param error set on error
3699 * Invokes the property's \c get method with the given arguments on the
3700 * object instance obj (or NULL for static properties).
3702 * If an exception is thrown, you can't use the
3703 * \c MonoObject* result from the function. The exception will be propagated via \p error.
3705 * \returns the value from invoking the get method on the property. On
3706 * failure returns NULL and sets \p error.
3709 mono_property_get_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3711 MONO_REQ_GC_UNSAFE_MODE;
3714 MonoObject *val = do_runtime_invoke (prop->get, obj, params, &exc, error);
3715 if (exc != NULL && !is_ok (error))
3716 mono_error_set_exception_instance (error, (MonoException*) exc);
3724 * mono_nullable_init:
3725 * @buf: The nullable structure to initialize.
3726 * @value: the value to initialize from
3727 * @klass: the type for the object
3729 * Initialize the nullable structure pointed to by @buf from @value which
3730 * should be a boxed value type. The size of @buf should be able to hold
3731 * as much data as the @klass->instance_size (which is the number of bytes
3732 * that will be copies).
3734 * Since Nullables have variable structure, we can not define a C
3735 * structure for them.
3738 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3740 MONO_REQ_GC_UNSAFE_MODE;
3742 MonoClass *param_class = klass->cast_class;
3744 mono_class_setup_fields (klass);
3745 g_assert (klass->fields_inited);
3747 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3748 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3750 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3752 if (param_class->has_references)
3753 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3755 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3757 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3762 * mono_nullable_box:
3763 * \param buf The buffer representing the data to be boxed
3764 * \param klass the type to box it as.
3765 * \param error set on error
3767 * Creates a boxed vtype or NULL from the \c Nullable structure pointed to by
3768 * \p buf. On failure returns NULL and sets \p error.
3771 mono_nullable_box (guint8 *buf, MonoClass *klass, MonoError *error)
3773 MONO_REQ_GC_UNSAFE_MODE;
3776 MonoClass *param_class = klass->cast_class;
3778 mono_class_setup_fields (klass);
3779 g_assert (klass->fields_inited);
3781 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3782 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3784 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3785 MonoObject *o = mono_object_new_checked (mono_domain_get (), param_class, error);
3786 return_val_if_nok (error, NULL);
3787 if (param_class->has_references)
3788 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3790 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3798 * mono_get_delegate_invoke:
3799 * \param klass The delegate class
3800 * \returns the \c MonoMethod for the \c Invoke method in the delegate class or NULL if \p klass is a broken delegate type
3803 mono_get_delegate_invoke (MonoClass *klass)
3805 MONO_REQ_GC_NEUTRAL_MODE;
3809 /* This is called at runtime, so avoid the slower search in metadata */
3810 mono_class_setup_methods (klass);
3811 if (mono_class_has_failure (klass))
3813 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3818 * mono_get_delegate_begin_invoke:
3819 * \param klass The delegate class
3820 * \returns the \c MonoMethod for the \c BeginInvoke method in the delegate class or NULL if \p klass is a broken delegate type
3823 mono_get_delegate_begin_invoke (MonoClass *klass)
3825 MONO_REQ_GC_NEUTRAL_MODE;
3829 /* This is called at runtime, so avoid the slower search in metadata */
3830 mono_class_setup_methods (klass);
3831 if (mono_class_has_failure (klass))
3833 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3838 * mono_get_delegate_end_invoke:
3839 * \param klass The delegate class
3840 * \returns the \c MonoMethod for the \c EndInvoke method in the delegate class or NULL if \p klass is a broken delegate type
3843 mono_get_delegate_end_invoke (MonoClass *klass)
3845 MONO_REQ_GC_NEUTRAL_MODE;
3849 /* This is called at runtime, so avoid the slower search in metadata */
3850 mono_class_setup_methods (klass);
3851 if (mono_class_has_failure (klass))
3853 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3858 * mono_runtime_delegate_invoke:
3859 * \param delegate pointer to a delegate object.
3860 * \param params parameters for the delegate.
3861 * \param exc Pointer to the exception result.
3863 * Invokes the delegate method \p delegate with the parameters provided.
3865 * You can pass NULL as the \p exc argument if you don't want to
3866 * catch exceptions, otherwise, \c *exc will be set to the exception
3867 * thrown, if any. if an exception is thrown, you can't use the
3868 * \c MonoObject* result from the function.
3871 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3873 MONO_REQ_GC_UNSAFE_MODE;
3877 MonoObject *result = mono_runtime_delegate_try_invoke (delegate, params, exc, &error);
3879 mono_error_cleanup (&error);
3882 if (!is_ok (&error))
3883 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
3887 MonoObject *result = mono_runtime_delegate_invoke_checked (delegate, params, &error);
3888 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
3894 * mono_runtime_delegate_try_invoke:
3895 * \param delegate pointer to a delegate object.
3896 * \param params parameters for the delegate.
3897 * \param exc Pointer to the exception result.
3898 * \param error set on error
3899 * Invokes the delegate method \p delegate with the parameters provided.
3901 * You can pass NULL as the \p exc argument if you don't want to
3902 * catch exceptions, otherwise, \c *exc will be set to the exception
3903 * thrown, if any. On failure to execute, \p error will be set.
3904 * if an exception is thrown, you can't use the
3905 * \c MonoObject* result from the function.
3908 mono_runtime_delegate_try_invoke (MonoObject *delegate, void **params, MonoObject **exc, MonoError *error)
3910 MONO_REQ_GC_UNSAFE_MODE;
3914 MonoClass *klass = delegate->vtable->klass;
3917 im = mono_get_delegate_invoke (klass);
3919 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3922 o = mono_runtime_try_invoke (im, delegate, params, exc, error);
3924 o = mono_runtime_invoke_checked (im, delegate, params, error);
3931 * mono_runtime_delegate_invoke_checked:
3932 * \param delegate pointer to a delegate object.
3933 * \param params parameters for the delegate.
3934 * \param error set on error
3935 * Invokes the delegate method \p delegate with the parameters provided.
3936 * On failure \p error will be set and you can't use the \c MonoObject*
3937 * result from the function.
3940 mono_runtime_delegate_invoke_checked (MonoObject *delegate, void **params, MonoError *error)
3943 return mono_runtime_delegate_try_invoke (delegate, params, NULL, error);
3946 static char **main_args = NULL;
3947 static int num_main_args = 0;
3950 * mono_runtime_get_main_args:
3951 * \returns A \c MonoArray with the arguments passed to the main program
3954 mono_runtime_get_main_args (void)
3956 MONO_REQ_GC_UNSAFE_MODE;
3958 MonoArray *result = mono_runtime_get_main_args_checked (&error);
3959 mono_error_assert_ok (&error);
3964 * mono_runtime_get_main_args_checked:
3965 * \param error set on error
3966 * \returns a \c MonoArray with the arguments passed to the main
3967 * program. On failure returns NULL and sets \p error.
3970 mono_runtime_get_main_args_checked (MonoError *error)
3974 MonoDomain *domain = mono_domain_get ();
3978 res = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, num_main_args, error);
3979 return_val_if_nok (error, NULL);
3981 for (i = 0; i < num_main_args; ++i) {
3982 MonoString *arg = mono_string_new_checked (domain, main_args [i], error);
3983 return_val_if_nok (error, NULL);
3984 mono_array_setref (res, i, arg);
3991 free_main_args (void)
3993 MONO_REQ_GC_NEUTRAL_MODE;
3997 for (i = 0; i < num_main_args; ++i)
3998 g_free (main_args [i]);
4005 * mono_runtime_set_main_args:
4006 * \param argc number of arguments from the command line
4007 * \param argv array of strings from the command line
4008 * Set the command line arguments from an embedding application that doesn't otherwise call
4009 * \c mono_runtime_run_main.
4012 mono_runtime_set_main_args (int argc, char* argv[])
4014 MONO_REQ_GC_NEUTRAL_MODE;
4019 main_args = g_new0 (char*, argc);
4020 num_main_args = argc;
4022 for (i = 0; i < argc; ++i) {
4025 utf8_arg = mono_utf8_from_external (argv[i]);
4026 if (utf8_arg == NULL) {
4027 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
4028 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4032 main_args [i] = utf8_arg;
4039 * Prepare an array of arguments in order to execute a standard Main()
4040 * method (argc/argv contains the executable name). This method also
4041 * sets the command line argument value needed by System.Environment.
4045 prepare_run_main (MonoMethod *method, int argc, char *argv[])
4047 MONO_REQ_GC_UNSAFE_MODE;
4051 MonoArray *args = NULL;
4052 MonoDomain *domain = mono_domain_get ();
4053 gchar *utf8_fullpath;
4054 MonoMethodSignature *sig;
4056 g_assert (method != NULL);
4058 mono_thread_set_main (mono_thread_current ());
4060 main_args = g_new0 (char*, argc);
4061 num_main_args = argc;
4063 if (!g_path_is_absolute (argv [0])) {
4064 gchar *basename = g_path_get_basename (argv [0]);
4065 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
4069 utf8_fullpath = mono_utf8_from_external (fullpath);
4070 if(utf8_fullpath == NULL) {
4071 /* Printing the arg text will cause glib to
4072 * whinge about "Invalid UTF-8", but at least
4073 * its relevant, and shows the problem text
4076 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
4077 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4084 utf8_fullpath = mono_utf8_from_external (argv[0]);
4085 if(utf8_fullpath == NULL) {
4086 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
4087 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4092 main_args [0] = utf8_fullpath;
4094 for (i = 1; i < argc; ++i) {
4097 utf8_arg=mono_utf8_from_external (argv[i]);
4098 if(utf8_arg==NULL) {
4099 /* Ditto the comment about Invalid UTF-8 here */
4100 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
4101 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4105 main_args [i] = utf8_arg;
4110 sig = mono_method_signature (method);
4112 g_print ("Unable to load Main method.\n");
4116 if (sig->param_count) {
4117 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, argc, &error);
4118 mono_error_assert_ok (&error);
4119 for (i = 0; i < argc; ++i) {
4120 /* The encodings should all work, given that
4121 * we've checked all these args for the
4124 gchar *str = mono_utf8_from_external (argv [i]);
4125 MonoString *arg = mono_string_new_checked (domain, str, &error);
4126 mono_error_assert_ok (&error);
4127 mono_array_setref (args, i, arg);
4131 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, 0, &error);
4132 mono_error_assert_ok (&error);
4135 mono_assembly_set_main (method->klass->image->assembly);
4141 * mono_runtime_run_main:
4142 * \param method the method to start the application with (usually <code>Main</code>)
4143 * \param argc number of arguments from the command line
4144 * \param argv array of strings from the command line
4145 * \param exc excetption results
4146 * Execute a standard \c Main method (\p argc / \p argv contains the
4147 * executable name). This method also sets the command line argument value
4148 * needed by \c System.Environment.
4151 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
4154 MONO_REQ_GC_UNSAFE_MODE;
4157 MonoArray *args = prepare_run_main (method, argc, argv);
4160 res = mono_runtime_try_exec_main (method, args, exc);
4162 res = mono_runtime_exec_main_checked (method, args, &error);
4163 mono_error_raise_exception (&error); /* OK to throw, external only without a better alternative */
4169 * mono_runtime_run_main_checked:
4170 * \param method the method to start the application with (usually \c Main)
4171 * \param argc number of arguments from the command line
4172 * \param argv array of strings from the command line
4173 * \param error set on error
4175 * Execute a standard \c Main method (\p argc / \p argv contains the
4176 * executable name). This method also sets the command line argument value
4177 * needed by \c System.Environment. On failure sets \p error.
4180 mono_runtime_run_main_checked (MonoMethod *method, int argc, char* argv[],
4184 MonoArray *args = prepare_run_main (method, argc, argv);
4185 return mono_runtime_exec_main_checked (method, args, error);
4189 * mono_runtime_try_run_main:
4190 * \param method the method to start the application with (usually \c Main)
4191 * \param argc number of arguments from the command line
4192 * \param argv array of strings from the command line
4193 * \param exc set if \c Main throws an exception
4194 * \param error set if \c Main can't be executed
4195 * Execute a standard \c Main method (\p argc / \p argv contains the executable
4196 * name). This method also sets the command line argument value needed
4197 * by \c System.Environment. On failure sets \p error if Main can't be
4198 * executed or \p exc if it threw an exception.
4201 mono_runtime_try_run_main (MonoMethod *method, int argc, char* argv[],
4205 MonoArray *args = prepare_run_main (method, argc, argv);
4206 return mono_runtime_try_exec_main (method, args, exc);
4211 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4213 static MonoMethod *serialize_method;
4219 if (!serialize_method) {
4220 MonoClass *klass = mono_class_get_remoting_services_class ();
4221 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
4224 if (!serialize_method) {
4229 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
4234 array = mono_runtime_try_invoke (serialize_method, NULL, params, exc, &error);
4235 if (*exc == NULL && !mono_error_ok (&error))
4236 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert serialize_object to MonoError */
4238 mono_error_cleanup (&error);
4247 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4249 MONO_REQ_GC_UNSAFE_MODE;
4251 static MonoMethod *deserialize_method;
4257 if (!deserialize_method) {
4258 MonoClass *klass = mono_class_get_remoting_services_class ();
4259 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
4261 if (!deserialize_method) {
4269 result = mono_runtime_try_invoke (deserialize_method, NULL, params, exc, &error);
4270 if (*exc == NULL && !mono_error_ok (&error))
4271 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert deserialize_object to MonoError */
4273 mono_error_cleanup (&error);
4281 #ifndef DISABLE_REMOTING
4283 make_transparent_proxy (MonoObject *obj, MonoError *error)
4285 MONO_REQ_GC_UNSAFE_MODE;
4287 static MonoMethod *get_proxy_method;
4289 MonoDomain *domain = mono_domain_get ();
4290 MonoRealProxy *real_proxy;
4291 MonoReflectionType *reflection_type;
4292 MonoTransparentProxy *transparent_proxy;
4296 if (!get_proxy_method)
4297 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
4299 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
4301 real_proxy = (MonoRealProxy*) mono_object_new_checked (domain, mono_defaults.real_proxy_class, error);
4302 return_val_if_nok (error, NULL);
4303 reflection_type = mono_type_get_object_checked (domain, &obj->vtable->klass->byval_arg, error);
4304 return_val_if_nok (error, NULL);
4306 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
4307 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
4309 MonoObject *exc = NULL;
4311 transparent_proxy = (MonoTransparentProxy*) mono_runtime_try_invoke (get_proxy_method, real_proxy, NULL, &exc, error);
4312 if (exc != NULL && is_ok (error))
4313 mono_error_set_exception_instance (error, (MonoException*)exc);
4315 return (MonoObject*) transparent_proxy;
4317 #endif /* DISABLE_REMOTING */
4320 * mono_object_xdomain_representation
4321 * \param obj an object
4322 * \param target_domain a domain
4323 * \param error set on error.
4324 * Creates a representation of obj in the domain \p target_domain. This
4325 * is either a copy of \p obj arrived through via serialization and
4326 * deserialization or a proxy, depending on whether the object is
4327 * serializable or marshal by ref. \p obj must not be in \p target_domain.
4328 * If the object cannot be represented in \p target_domain, NULL is
4329 * returned and \p error is set appropriately.
4332 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoError *error)
4334 MONO_REQ_GC_UNSAFE_MODE;
4337 MonoObject *deserialized = NULL;
4339 #ifndef DISABLE_REMOTING
4340 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
4341 deserialized = make_transparent_proxy (obj, error);
4346 gboolean failure = FALSE;
4347 MonoDomain *domain = mono_domain_get ();
4348 MonoObject *serialized;
4349 MonoObject *exc = NULL;
4351 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
4352 serialized = serialize_object (obj, &failure, &exc);
4353 mono_domain_set_internal_with_options (target_domain, FALSE);
4355 deserialized = deserialize_object (serialized, &failure, &exc);
4356 if (domain != target_domain)
4357 mono_domain_set_internal_with_options (domain, FALSE);
4359 mono_error_set_exception_instance (error, (MonoException*)exc);
4362 return deserialized;
4365 /* Used in call_unhandled_exception_delegate */
4367 create_unhandled_exception_eventargs (MonoObject *exc, MonoError *error)
4369 MONO_REQ_GC_UNSAFE_MODE;
4374 MonoMethod *method = NULL;
4375 MonoBoolean is_terminating = TRUE;
4378 klass = mono_class_get_unhandled_exception_event_args_class ();
4379 mono_class_init (klass);
4381 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4382 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
4386 args [1] = &is_terminating;
4388 obj = mono_object_new_checked (mono_domain_get (), klass, error);
4389 return_val_if_nok (error, NULL);
4391 mono_runtime_invoke_checked (method, obj, args, error);
4392 return_val_if_nok (error, NULL);
4397 /* Used in mono_unhandled_exception */
4399 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4400 MONO_REQ_GC_UNSAFE_MODE;
4403 MonoObject *e = NULL;
4405 MonoDomain *current_domain = mono_domain_get ();
4407 if (domain != current_domain)
4408 mono_domain_set_internal_with_options (domain, FALSE);
4410 g_assert (domain == mono_object_domain (domain->domain));
4412 if (mono_object_domain (exc) != domain) {
4414 exc = mono_object_xdomain_representation (exc, domain, &error);
4416 if (!is_ok (&error)) {
4417 MonoError inner_error;
4418 MonoException *serialization_exc = mono_error_convert_to_exception (&error);
4419 exc = mono_object_xdomain_representation ((MonoObject*)serialization_exc, domain, &inner_error);
4420 mono_error_assert_ok (&inner_error);
4422 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4423 "System.Runtime.Serialization", "SerializationException",
4424 "Could not serialize unhandled exception.");
4428 g_assert (mono_object_domain (exc) == domain);
4430 pa [0] = domain->domain;
4431 pa [1] = create_unhandled_exception_eventargs (exc, &error);
4432 mono_error_assert_ok (&error);
4433 mono_runtime_delegate_try_invoke (delegate, pa, &e, &error);
4434 if (!is_ok (&error)) {
4436 e = (MonoObject*)mono_error_convert_to_exception (&error);
4438 mono_error_cleanup (&error);
4441 if (domain != current_domain)
4442 mono_domain_set_internal_with_options (current_domain, FALSE);
4445 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4446 if (!mono_error_ok (&error)) {
4447 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4448 mono_error_cleanup (&error);
4450 g_warning ("exception inside UnhandledException handler: %s\n", msg);
4456 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4459 * mono_runtime_unhandled_exception_policy_set:
4460 * \param policy the new policy
4461 * This is a VM internal routine.
4462 * Sets the runtime policy for handling unhandled exceptions.
4465 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4466 runtime_unhandled_exception_policy = policy;
4470 * mono_runtime_unhandled_exception_policy_get:
4472 * This is a VM internal routine.
4474 * Gets the runtime policy for handling unhandled exceptions.
4476 MonoRuntimeUnhandledExceptionPolicy
4477 mono_runtime_unhandled_exception_policy_get (void) {
4478 return runtime_unhandled_exception_policy;
4482 * mono_unhandled_exception:
4483 * \param exc exception thrown
4484 * This is a VM internal routine.
4486 * We call this function when we detect an unhandled exception
4487 * in the default domain.
4489 * It invokes the \c UnhandledException event in \c AppDomain or prints
4490 * a warning to the console
4493 mono_unhandled_exception (MonoObject *exc_raw)
4496 HANDLE_FUNCTION_ENTER ();
4497 MONO_HANDLE_DCL (MonoObject, exc);
4498 error_init (&error);
4499 mono_unhandled_exception_checked (exc, &error);
4500 mono_error_assert_ok (&error);
4501 HANDLE_FUNCTION_RETURN ();
4505 * mono_unhandled_exception:
4506 * @exc: exception thrown
4508 * This is a VM internal routine.
4510 * We call this function when we detect an unhandled exception
4511 * in the default domain.
4513 * It invokes the * UnhandledException event in AppDomain or prints
4514 * a warning to the console
4517 mono_unhandled_exception_checked (MonoObjectHandle exc, MonoError *error)
4519 MONO_REQ_GC_UNSAFE_MODE;
4522 MonoClassField *field;
4523 MonoDomain *current_domain, *root_domain;
4524 MonoObjectHandle current_appdomain_delegate = MONO_HANDLE_NEW (MonoObject, NULL);
4526 MonoClass *klass = mono_handle_class (exc);
4527 if (mono_class_has_parent (klass, mono_defaults.threadabortexception_class))
4530 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4533 current_domain = mono_domain_get ();
4534 root_domain = mono_get_root_domain ();
4536 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 */
4537 return_if_nok (error);
4538 if (current_domain != root_domain) {
4539 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 */
4540 return_if_nok (error);
4543 if (MONO_HANDLE_IS_NULL (current_appdomain_delegate) && MONO_HANDLE_IS_NULL (root_appdomain_delegate)) {
4544 mono_print_unhandled_exception (MONO_HANDLE_RAW (exc)); /* FIXME use handles for mono_print_unhandled_exception */
4546 /* unhandled exception callbacks must not be aborted */
4547 mono_threads_begin_abort_protected_block ();
4548 if (!MONO_HANDLE_IS_NULL (root_appdomain_delegate))
4549 call_unhandled_exception_delegate (root_domain, MONO_HANDLE_RAW (root_appdomain_delegate), MONO_HANDLE_RAW (exc)); /* FIXME use handles in call_unhandled_exception_delegate */
4550 if (!MONO_HANDLE_IS_NULL (current_appdomain_delegate))
4551 call_unhandled_exception_delegate (current_domain, MONO_HANDLE_RAW (current_appdomain_delegate), MONO_HANDLE_RAW (exc));
4552 mono_threads_end_abort_protected_block ();
4555 /* set exitcode only if we will abort the process */
4556 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4557 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4559 mono_environment_exitcode_set (1);
4564 * mono_runtime_exec_managed_code:
4565 * \param domain Application domain
4566 * \param main_func function to invoke from the execution thread
4567 * \param main_args parameter to the main_func
4568 * Launch a new thread to execute a function
4570 * \p main_func is called back from the thread with main_args as the
4571 * parameter. The callback function is expected to start \c Main
4572 * eventually. This function then waits for all managed threads to
4574 * It is not necessary anymore to execute managed code in a subthread,
4575 * so this function should not be used anymore by default: just
4576 * execute the code and then call mono_thread_manage().
4579 mono_runtime_exec_managed_code (MonoDomain *domain,
4580 MonoMainThreadFunc main_func,
4584 mono_thread_create_checked (domain, main_func, main_args, &error);
4585 mono_error_assert_ok (&error);
4587 mono_thread_manage ();
4591 prepare_thread_to_exec_main (MonoDomain *domain, MonoMethod *method)
4593 MonoInternalThread* thread = mono_thread_internal_current ();
4594 MonoCustomAttrInfo* cinfo;
4595 gboolean has_stathread_attribute;
4597 if (!domain->entry_assembly) {
4600 MonoAssembly *assembly;
4602 assembly = method->klass->image->assembly;
4603 domain->entry_assembly = assembly;
4604 /* Domains created from another domain already have application_base and configuration_file set */
4605 if (domain->setup->application_base == NULL) {
4606 MonoString *basedir = mono_string_new_checked (domain, assembly->basedir, &error);
4607 mono_error_assert_ok (&error);
4608 MONO_OBJECT_SETREF (domain->setup, application_base, basedir);
4611 if (domain->setup->configuration_file == NULL) {
4612 str = g_strconcat (assembly->image->name, ".config", NULL);
4613 MonoString *config_file = mono_string_new_checked (domain, str, &error);
4614 mono_error_assert_ok (&error);
4615 MONO_OBJECT_SETREF (domain->setup, configuration_file, config_file);
4617 mono_domain_set_options_from_config (domain);
4621 MonoError cattr_error;
4622 cinfo = mono_custom_attrs_from_method_checked (method, &cattr_error);
4623 mono_error_cleanup (&cattr_error); /* FIXME warn here? */
4625 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, mono_class_get_sta_thread_attribute_class ());
4627 mono_custom_attrs_free (cinfo);
4629 has_stathread_attribute = FALSE;
4631 if (has_stathread_attribute) {
4632 thread->apartment_state = ThreadApartmentState_STA;
4634 thread->apartment_state = ThreadApartmentState_MTA;
4636 mono_thread_init_apartment_state ();
4641 do_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4643 MONO_REQ_GC_UNSAFE_MODE;
4653 /* FIXME: check signature of method */
4654 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4656 res = mono_runtime_invoke_checked (method, NULL, pa, error);
4658 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4661 mono_environment_exitcode_set (rval);
4663 mono_runtime_invoke_checked (method, NULL, pa, error);
4675 do_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4677 MONO_REQ_GC_UNSAFE_MODE;
4687 /* FIXME: check signature of method */
4688 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4689 MonoError inner_error;
4691 res = mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4692 if (*exc == NULL && !mono_error_ok (&inner_error))
4693 *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4695 mono_error_cleanup (&inner_error);
4698 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4702 mono_environment_exitcode_set (rval);
4704 MonoError inner_error;
4705 mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4706 if (*exc == NULL && !mono_error_ok (&inner_error))
4707 *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4709 mono_error_cleanup (&inner_error);
4714 /* If the return type of Main is void, only
4715 * set the exitcode if an exception was thrown
4716 * (we don't want to blow away an
4717 * explicitly-set exit code)
4720 mono_environment_exitcode_set (rval);
4728 * Execute a standard Main() method (args doesn't contain the
4732 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4735 prepare_thread_to_exec_main (mono_object_domain (args), method);
4737 int rval = do_try_exec_main (method, args, exc);
4740 int rval = do_exec_main_checked (method, args, &error);
4741 mono_error_raise_exception (&error); /* OK to throw, external only with no better option */
4747 * Execute a standard Main() method (args doesn't contain the
4750 * On failure sets @error
4753 mono_runtime_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4756 prepare_thread_to_exec_main (mono_object_domain (args), method);
4757 return do_exec_main_checked (method, args, error);
4761 * Execute a standard Main() method (args doesn't contain the
4764 * On failure sets @error if Main couldn't be executed, or @exc if it threw an exception.
4767 mono_runtime_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4769 prepare_thread_to_exec_main (mono_object_domain (args), method);
4770 return do_try_exec_main (method, args, exc);
4775 /** invoke_array_extract_argument:
4776 * @params: array of arguments to the method.
4777 * @i: the index of the argument to extract.
4778 * @t: ith type from the method signature.
4779 * @has_byref_nullables: outarg - TRUE if method expects a byref nullable argument
4780 * @error: set on error.
4782 * Given an array of method arguments, return the ith one using the corresponding type
4783 * to perform necessary unboxing. If method expects a ref nullable argument, writes TRUE to @has_byref_nullables.
4785 * On failure sets @error and returns NULL.
4788 invoke_array_extract_argument (MonoArray *params, int i, MonoType *t, gboolean* has_byref_nullables, MonoError *error)
4790 MonoType *t_orig = t;
4791 gpointer result = NULL;
4797 case MONO_TYPE_BOOLEAN:
4800 case MONO_TYPE_CHAR:
4809 case MONO_TYPE_VALUETYPE:
4810 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (t_orig))) {
4811 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4812 result = mono_array_get (params, MonoObject*, i);
4814 *has_byref_nullables = TRUE;
4816 /* MS seems to create the objects if a null is passed in */
4817 gboolean was_null = FALSE;
4818 if (!mono_array_get (params, MonoObject*, i)) {
4819 MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (t_orig), error);
4820 return_val_if_nok (error, NULL);
4821 mono_array_setref (params, i, o);
4827 * We can't pass the unboxed vtype byref to the callee, since
4828 * that would mean the callee would be able to modify boxed
4829 * primitive types. So we (and MS) make a copy of the boxed
4830 * object, pass that to the callee, and replace the original
4831 * boxed object in the arg array with the copy.
4833 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4834 MonoObject *copy = mono_value_box_checked (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig), error);
4835 return_val_if_nok (error, NULL);
4836 mono_array_setref (params, i, copy);
4839 result = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4840 if (!t->byref && was_null)
4841 mono_array_setref (params, i, NULL);
4844 case MONO_TYPE_STRING:
4845 case MONO_TYPE_OBJECT:
4846 case MONO_TYPE_CLASS:
4847 case MONO_TYPE_ARRAY:
4848 case MONO_TYPE_SZARRAY:
4850 result = mono_array_addr (params, MonoObject*, i);
4851 // FIXME: I need to check this code path
4853 result = mono_array_get (params, MonoObject*, i);
4855 case MONO_TYPE_GENERICINST:
4857 t = &t->data.generic_class->container_class->this_arg;
4859 t = &t->data.generic_class->container_class->byval_arg;
4861 case MONO_TYPE_PTR: {
4864 /* The argument should be an IntPtr */
4865 arg = mono_array_get (params, MonoObject*, i);
4869 g_assert (arg->vtable->klass == mono_defaults.int_class);
4870 result = ((MonoIntPtr*)arg)->m_value;
4875 g_error ("type 0x%x not handled in mono_runtime_invoke_array", t_orig->type);
4880 * mono_runtime_invoke_array:
4881 * \param method method to invoke
4882 * \param obj object instance
4883 * \param params arguments to the method
4884 * \param exc exception information.
4885 * Invokes the method represented by \p method on the object \p obj.
4887 * \p obj is the \c this pointer, it should be NULL for static
4888 * methods, a \c MonoObject* for object instances and a pointer to
4889 * the value type for value types.
4891 * The \p params array contains the arguments to the method with the
4892 * same convention: \c MonoObject* pointers for object instances and
4893 * pointers to the value type otherwise. The \c _invoke_array
4894 * variant takes a C# \c object[] as the params argument (\c MonoArray*):
4895 * in this case the value types are boxed inside the
4896 * respective reference representation.
4898 * From unmanaged code you'll usually use the
4899 * mono_runtime_invoke_checked() variant.
4901 * Note that this function doesn't handle virtual methods for
4902 * you, it will exec the exact method you pass: we still need to
4903 * expose a function to lookup the derived class implementation
4904 * of a virtual method (there are examples of this in the code,
4907 * You can pass NULL as the \p exc argument if you don't want to
4908 * catch exceptions, otherwise, \c *exc will be set to the exception
4909 * thrown, if any. if an exception is thrown, you can't use the
4910 * \c MonoObject* result from the function.
4912 * If the method returns a value type, it is boxed in an object
4916 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4921 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, exc, &error);
4923 mono_error_cleanup (&error);
4926 if (!is_ok (&error))
4927 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
4931 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, NULL, &error);
4932 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
4938 * mono_runtime_invoke_array_checked:
4939 * \param method method to invoke
4940 * \param obj object instance
4941 * \param params arguments to the method
4942 * \param error set on failure.
4943 * Invokes the method represented by \p method on the object \p obj.
4945 * \p obj is the \c this pointer, it should be NULL for static
4946 * methods, a \c MonoObject* for object instances and a pointer to
4947 * the value type for value types.
4949 * The \p params array contains the arguments to the method with the
4950 * same convention: \c MonoObject* pointers for object instances and
4951 * pointers to the value type otherwise. The \c _invoke_array
4952 * variant takes a C# \c object[] as the \p params argument (\c MonoArray*):
4953 * in this case the value types are boxed inside the
4954 * respective reference representation.
4956 * From unmanaged code you'll usually use the
4957 * mono_runtime_invoke_checked() variant.
4959 * Note that this function doesn't handle virtual methods for
4960 * you, it will exec the exact method you pass: we still need to
4961 * expose a function to lookup the derived class implementation
4962 * of a virtual method (there are examples of this in the code,
4965 * On failure or exception, \p error will be set. In that case, you
4966 * can't use the \c MonoObject* result from the function.
4968 * If the method returns a value type, it is boxed in an object
4972 mono_runtime_invoke_array_checked (MonoMethod *method, void *obj, MonoArray *params,
4976 return mono_runtime_try_invoke_array (method, obj, params, NULL, error);
4980 * mono_runtime_try_invoke_array:
4981 * \param method method to invoke
4982 * \param obj object instance
4983 * \param params arguments to the method
4984 * \param exc exception information.
4985 * \param error set on failure.
4986 * Invokes the method represented by \p method on the object \p obj.
4988 * \p obj is the \c this pointer, it should be NULL for static
4989 * methods, a \c MonoObject* for object instances and a pointer to
4990 * the value type for value types.
4992 * The \p params array contains the arguments to the method with the
4993 * same convention: \c MonoObject* pointers for object instances and
4994 * pointers to the value type otherwise. The \c _invoke_array
4995 * variant takes a C# \c object[] as the params argument (\c MonoArray*):
4996 * in this case the value types are boxed inside the
4997 * respective reference representation.
4999 * From unmanaged code you'll usually use the
5000 * mono_runtime_invoke_checked() variant.
5002 * Note that this function doesn't handle virtual methods for
5003 * you, it will exec the exact method you pass: we still need to
5004 * expose a function to lookup the derived class implementation
5005 * of a virtual method (there are examples of this in the code,
5008 * You can pass NULL as the \p exc argument if you don't want to catch
5009 * exceptions, otherwise, \c *exc will be set to the exception thrown, if
5010 * any. On other failures, \p error will be set. If an exception is
5011 * thrown or there's an error, you can't use the \c MonoObject* result
5012 * from the function.
5014 * If the method returns a value type, it is boxed in an object
5018 mono_runtime_try_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
5019 MonoObject **exc, MonoError *error)
5021 MONO_REQ_GC_UNSAFE_MODE;
5025 MonoMethodSignature *sig = mono_method_signature (method);
5026 gpointer *pa = NULL;
5029 gboolean has_byref_nullables = FALSE;
5031 if (NULL != params) {
5032 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
5033 for (i = 0; i < mono_array_length (params); i++) {
5034 MonoType *t = sig->params [i];
5035 pa [i] = invoke_array_extract_argument (params, i, t, &has_byref_nullables, error);
5036 return_val_if_nok (error, NULL);
5040 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
5043 if (mono_class_is_nullable (method->klass)) {
5044 /* Need to create a boxed vtype instead */
5050 return mono_value_box_checked (mono_domain_get (), method->klass->cast_class, pa [0], error);
5055 obj = mono_object_new_checked (mono_domain_get (), method->klass, error);
5056 mono_error_assert_ok (error);
5057 g_assert (obj); /*maybe we should raise a TLE instead?*/
5058 #ifndef DISABLE_REMOTING
5059 if (mono_object_is_transparent_proxy (obj)) {
5060 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
5063 if (method->klass->valuetype)
5064 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
5067 } else if (method->klass->valuetype) {
5068 obj = mono_value_box_checked (mono_domain_get (), method->klass, obj, error);
5069 return_val_if_nok (error, NULL);
5073 mono_runtime_try_invoke (method, o, pa, exc, error);
5075 mono_runtime_invoke_checked (method, o, pa, error);
5078 return (MonoObject *)obj;
5080 if (mono_class_is_nullable (method->klass)) {
5081 MonoObject *nullable;
5083 /* Convert the unboxed vtype into a Nullable structure */
5084 nullable = mono_object_new_checked (mono_domain_get (), method->klass, error);
5085 return_val_if_nok (error, NULL);
5087 MonoObject *boxed = mono_value_box_checked (mono_domain_get (), method->klass->cast_class, obj, error);
5088 return_val_if_nok (error, NULL);
5089 mono_nullable_init ((guint8 *)mono_object_unbox (nullable), boxed, method->klass);
5090 obj = mono_object_unbox (nullable);
5093 /* obj must be already unboxed if needed */
5095 res = mono_runtime_try_invoke (method, obj, pa, exc, error);
5097 res = mono_runtime_invoke_checked (method, obj, pa, error);
5099 return_val_if_nok (error, NULL);
5101 if (sig->ret->type == MONO_TYPE_PTR) {
5102 MonoClass *pointer_class;
5103 static MonoMethod *box_method;
5105 MonoObject *box_exc;
5108 * The runtime-invoke wrapper returns a boxed IntPtr, need to
5109 * convert it to a Pointer object.
5111 pointer_class = mono_class_get_pointer_class ();
5113 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
5115 g_assert (res->vtable->klass == mono_defaults.int_class);
5116 box_args [0] = ((MonoIntPtr*)res)->m_value;
5117 box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, error);
5118 return_val_if_nok (error, NULL);
5120 res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, error);
5121 g_assert (box_exc == NULL);
5122 mono_error_assert_ok (error);
5125 if (has_byref_nullables) {
5127 * The runtime invoke wrapper already converted byref nullables back,
5128 * and stored them in pa, we just need to copy them back to the
5131 for (i = 0; i < mono_array_length (params); i++) {
5132 MonoType *t = sig->params [i];
5134 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
5135 mono_array_setref (params, i, pa [i]);
5145 * \param klass the class of the object that we want to create
5146 * \returns a newly created object whose definition is
5147 * looked up using \p klass. This will not invoke any constructors,
5148 * so the consumer of this routine has to invoke any constructors on
5149 * its own to initialize the object.
5151 * It returns NULL on failure.
5154 mono_object_new (MonoDomain *domain, MonoClass *klass)
5156 MONO_REQ_GC_UNSAFE_MODE;
5160 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5162 mono_error_cleanup (&error);
5167 ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
5169 MONO_REQ_GC_UNSAFE_MODE;
5173 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5175 mono_error_set_pending_exception (&error);
5180 * mono_object_new_checked:
5181 * \param klass the class of the object that we want to create
5182 * \param error set on error
5183 * \returns a newly created object whose definition is
5184 * looked up using \p klass. This will not invoke any constructors,
5185 * so the consumer of this routine has to invoke any constructors on
5186 * its own to initialize the object.
5188 * It returns NULL on failure and sets \p error.
5191 mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
5193 MONO_REQ_GC_UNSAFE_MODE;
5197 vtable = mono_class_vtable (domain, klass);
5198 g_assert (vtable); /* FIXME don't swallow the error */
5200 MonoObject *o = mono_object_new_specific_checked (vtable, error);
5205 * mono_object_new_pinned:
5207 * Same as mono_object_new, but the returned object will be pinned.
5208 * For SGEN, these objects will only be freed at appdomain unload.
5211 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
5213 MONO_REQ_GC_UNSAFE_MODE;
5219 vtable = mono_class_vtable (domain, klass);
5220 g_assert (vtable); /* FIXME don't swallow the error */
5222 MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
5224 if (G_UNLIKELY (!o))
5225 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
5226 else if (G_UNLIKELY (vtable->klass->has_finalize))
5227 mono_object_register_finalizer (o);
5233 * mono_object_new_specific:
5234 * \param vtable the vtable of the object that we want to create
5235 * \returns A newly created object with class and domain specified
5239 mono_object_new_specific (MonoVTable *vtable)
5242 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5243 mono_error_cleanup (&error);
5249 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
5251 MONO_REQ_GC_UNSAFE_MODE;
5257 /* check for is_com_object for COM Interop */
5258 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
5261 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
5264 MonoClass *klass = mono_class_get_activation_services_class ();
5267 mono_class_init (klass);
5269 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
5271 mono_error_set_not_supported (error, "Linked away.");
5274 vtable->domain->create_proxy_for_type_method = im;
5277 pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
5278 if (!mono_error_ok (error))
5281 o = mono_runtime_invoke_checked (im, NULL, pa, error);
5282 if (!mono_error_ok (error))
5289 return mono_object_new_alloc_specific_checked (vtable, error);
5293 ves_icall_object_new_specific (MonoVTable *vtable)
5296 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5297 mono_error_set_pending_exception (&error);
5303 * mono_object_new_alloc_specific:
5304 * \param vtable virtual table for the object.
5305 * This function allocates a new \c MonoObject with the type derived
5306 * from the \p vtable information. If the class of this object has a
5307 * finalizer, then the object will be tracked for finalization.
5309 * This method might raise an exception on errors. Use the
5310 * \c mono_object_new_fast_checked method if you want to manually raise
5313 * \returns the allocated object.
5316 mono_object_new_alloc_specific (MonoVTable *vtable)
5319 MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
5320 mono_error_cleanup (&error);
5326 * mono_object_new_alloc_specific_checked:
5327 * \param vtable virtual table for the object.
5328 * \param error holds the error return value.
5330 * This function allocates a new \c MonoObject with the type derived
5331 * from the \p vtable information. If the class of this object has a
5332 * finalizer, then the object will be tracked for finalization.
5334 * If there is not enough memory, the \p error parameter will be set
5335 * and will contain a user-visible message with the amount of bytes
5336 * that were requested.
5338 * \returns the allocated object, or NULL if there is not enough memory
5341 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
5343 MONO_REQ_GC_UNSAFE_MODE;
5349 o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5351 if (G_UNLIKELY (!o))
5352 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5353 else if (G_UNLIKELY (vtable->klass->has_finalize))
5354 mono_object_register_finalizer (o);
5360 * mono_object_new_fast:
5361 * \param vtable virtual table for the object.
5363 * This function allocates a new \c MonoObject with the type derived
5364 * from the \p vtable information. The returned object is not tracked
5365 * for finalization. If your object implements a finalizer, you should
5366 * use \c mono_object_new_alloc_specific instead.
5368 * This method might raise an exception on errors. Use the
5369 * \c mono_object_new_fast_checked method if you want to manually raise
5372 * \returns the allocated object.
5375 mono_object_new_fast (MonoVTable *vtable)
5378 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5379 mono_error_cleanup (&error);
5385 * mono_object_new_fast_checked:
5386 * \param vtable virtual table for the object.
5387 * \param error holds the error return value.
5389 * This function allocates a new \c MonoObject with the type derived
5390 * from the \p vtable information. The returned object is not tracked
5391 * for finalization. If your object implements a finalizer, you should
5392 * use \c mono_object_new_alloc_specific_checked instead.
5394 * If there is not enough memory, the \p error parameter will be set
5395 * and will contain a user-visible message with the amount of bytes
5396 * that were requested.
5398 * \returns the allocated object, or NULL if there is not enough memory
5401 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
5403 MONO_REQ_GC_UNSAFE_MODE;
5409 o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5411 if (G_UNLIKELY (!o))
5412 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5418 ves_icall_object_new_fast (MonoVTable *vtable)
5421 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5422 mono_error_set_pending_exception (&error);
5428 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
5430 MONO_REQ_GC_UNSAFE_MODE;
5436 o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
5438 if (G_UNLIKELY (!o))
5439 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5440 else if (G_UNLIKELY (vtable->klass->has_finalize))
5441 mono_object_register_finalizer (o);
5447 * mono_class_get_allocation_ftn:
5448 * \param vtable vtable
5449 * \param for_box the object will be used for boxing
5450 * \param pass_size_in_words Unused
5451 * \returns the allocation function appropriate for the given class.
5454 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
5456 MONO_REQ_GC_NEUTRAL_MODE;
5458 *pass_size_in_words = FALSE;
5460 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass))
5461 return ves_icall_object_new_specific;
5463 if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
5465 return ves_icall_object_new_fast;
5468 * FIXME: This is actually slower than ves_icall_object_new_fast, because
5469 * of the overhead of parameter passing.
5472 *pass_size_in_words = TRUE;
5473 #ifdef GC_REDIRECT_TO_LOCAL
5474 return GC_local_gcj_fast_malloc;
5476 return GC_gcj_fast_malloc;
5481 return ves_icall_object_new_specific;
5485 * mono_object_new_from_token:
5486 * \param image Context where the type_token is hosted
5487 * \param token a token of the type that we want to create
5488 * \returns A newly created object whose definition is
5489 * looked up using \p token in the \p image image
5492 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
5494 MONO_REQ_GC_UNSAFE_MODE;
5500 klass = mono_class_get_checked (image, token, &error);
5501 mono_error_assert_ok (&error);
5503 result = mono_object_new_checked (domain, klass, &error);
5505 mono_error_cleanup (&error);
5512 * mono_object_clone:
5513 * \param obj the object to clone
5514 * \returns A newly created object who is a shallow copy of \p obj
5517 mono_object_clone (MonoObject *obj)
5520 MonoObject *o = mono_object_clone_checked (obj, &error);
5521 mono_error_cleanup (&error);
5527 mono_object_clone_checked (MonoObject *obj, MonoError *error)
5529 MONO_REQ_GC_UNSAFE_MODE;
5536 size = obj->vtable->klass->instance_size;
5538 if (obj->vtable->klass->rank)
5539 return (MonoObject*)mono_array_clone_checked ((MonoArray*)obj, error);
5541 o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
5543 if (G_UNLIKELY (!o)) {
5544 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5548 /* If the object doesn't contain references this will do a simple memmove. */
5549 mono_gc_wbarrier_object_copy (o, obj);
5551 if (obj->vtable->klass->has_finalize)
5552 mono_object_register_finalizer (o);
5557 * mono_array_full_copy:
5558 * \param src source array to copy
5559 * \param dest destination array
5560 * Copies the content of one array to another with exactly the same type and size.
5563 mono_array_full_copy (MonoArray *src, MonoArray *dest)
5565 MONO_REQ_GC_UNSAFE_MODE;
5568 MonoClass *klass = src->obj.vtable->klass;
5570 g_assert (klass == dest->obj.vtable->klass);
5572 size = mono_array_length (src);
5573 g_assert (size == mono_array_length (dest));
5574 size *= mono_array_element_size (klass);
5576 array_full_copy_unchecked_size (src, dest, klass, size);
5580 array_full_copy_unchecked_size (MonoArray *src, MonoArray *dest, MonoClass *klass, uintptr_t size)
5583 if (klass->element_class->valuetype) {
5584 if (klass->element_class->has_references)
5585 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
5587 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5589 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
5592 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5597 * mono_array_clone_in_domain:
5598 * \param domain the domain in which the array will be cloned into
5599 * \param array the array to clone
5600 * \param error set on error
5601 * This routine returns a copy of the array that is hosted on the
5602 * specified \c MonoDomain. On failure returns NULL and sets \p error.
5605 mono_array_clone_in_domain (MonoDomain *domain, MonoArrayHandle array_handle, MonoError *error)
5607 MONO_REQ_GC_UNSAFE_MODE;
5609 MonoArrayHandle result = MONO_HANDLE_NEW (MonoArray, NULL);
5611 MonoClass *klass = mono_handle_class (array_handle);
5615 /* Pin source array here - if bounds is non-NULL, it's a pointer into the object data */
5616 uint32_t src_handle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, array_handle), TRUE);
5618 MonoArrayBounds *array_bounds = MONO_HANDLE_GETVAL (array_handle, bounds);
5620 if (array_bounds == NULL) {
5621 size = mono_array_handle_length (array_handle);
5622 o = mono_array_new_full_handle (domain, klass, &size, NULL, error);
5625 size *= mono_array_element_size (klass);
5627 uintptr_t *sizes = (uintptr_t *)alloca (klass->rank * sizeof (uintptr_t));
5628 intptr_t *lower_bounds = (intptr_t *)alloca (klass->rank * sizeof (intptr_t));
5629 size = mono_array_element_size (klass);
5630 for (int i = 0; i < klass->rank; ++i) {
5631 sizes [i] = array_bounds [i].length;
5632 size *= array_bounds [i].length;
5633 lower_bounds [i] = array_bounds [i].lower_bound;
5635 o = mono_array_new_full_handle (domain, klass, sizes, lower_bounds, error);
5640 uint32_t dst_handle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, o), TRUE);
5641 array_full_copy_unchecked_size (MONO_HANDLE_RAW (array_handle), MONO_HANDLE_RAW (o), klass, size);
5642 mono_gchandle_free (dst_handle);
5644 MONO_HANDLE_ASSIGN (result, o);
5647 mono_gchandle_free (src_handle);
5653 * \param array the array to clone
5654 * \returns A newly created array who is a shallow copy of \p array
5657 mono_array_clone (MonoArray *array)
5659 MONO_REQ_GC_UNSAFE_MODE;
5662 MonoArray *result = mono_array_clone_checked (array, &error);
5663 mono_error_cleanup (&error);
5668 * mono_array_clone_checked:
5669 * \param array the array to clone
5670 * \param error set on error
5671 * \returns A newly created array who is a shallow copy of \p array. On
5672 * failure returns NULL and sets \p error.
5675 mono_array_clone_checked (MonoArray *array_raw, MonoError *error)
5677 MONO_REQ_GC_UNSAFE_MODE;
5678 HANDLE_FUNCTION_ENTER ();
5679 /* FIXME: callers of mono_array_clone_checked should use handles */
5681 MONO_HANDLE_DCL (MonoArray, array);
5682 MonoArrayHandle result = mono_array_clone_in_domain (MONO_HANDLE_DOMAIN (array), array, error);
5683 HANDLE_FUNCTION_RETURN_OBJ (result);
5686 /* helper macros to check for overflow when calculating the size of arrays */
5687 #ifdef MONO_BIG_ARRAYS
5688 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
5689 #define MYGUINT_MAX MYGUINT64_MAX
5690 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5691 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
5692 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5693 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
5694 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
5696 #define MYGUINT32_MAX 4294967295U
5697 #define MYGUINT_MAX MYGUINT32_MAX
5698 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5699 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
5700 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5701 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
5702 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
5706 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
5708 MONO_REQ_GC_NEUTRAL_MODE;
5712 byte_len = mono_array_element_size (klass);
5713 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
5716 if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
5718 byte_len += MONO_SIZEOF_MONO_ARRAY;
5726 * mono_array_new_full:
5727 * \param domain domain where the object is created
5728 * \param array_class array class
5729 * \param lengths lengths for each dimension in the array
5730 * \param lower_bounds lower bounds for each dimension in the array (may be NULL)
5731 * This routine creates a new array object with the given dimensions,
5732 * lower bounds and type.
5735 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
5738 MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
5739 mono_error_cleanup (&error);
5745 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
5747 MONO_REQ_GC_UNSAFE_MODE;
5749 uintptr_t byte_len = 0, len, bounds_size;
5752 MonoArrayBounds *bounds;
5758 if (!array_class->inited)
5759 mono_class_init (array_class);
5763 /* A single dimensional array with a 0 lower bound is the same as an szarray */
5764 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
5766 if (len > MONO_ARRAY_MAX_INDEX) {
5767 mono_error_set_generic_error (error, "System", "OverflowException", "");
5772 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
5774 for (i = 0; i < array_class->rank; ++i) {
5775 if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
5776 mono_error_set_generic_error (error, "System", "OverflowException", "");
5779 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5780 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5787 if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5788 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5794 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5795 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5798 byte_len = (byte_len + 3) & ~3;
5799 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5800 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5803 byte_len += bounds_size;
5806 * Following three lines almost taken from mono_object_new ():
5807 * they need to be kept in sync.
5809 vtable = mono_class_vtable_full (domain, array_class, error);
5810 return_val_if_nok (error, NULL);
5813 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5815 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5817 if (G_UNLIKELY (!o)) {
5818 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5822 array = (MonoArray*)o;
5824 bounds = array->bounds;
5827 for (i = 0; i < array_class->rank; ++i) {
5828 bounds [i].length = lengths [i];
5830 bounds [i].lower_bound = lower_bounds [i];
5839 * \param domain domain where the object is created
5840 * \param eclass element class
5841 * \param n number of array elements
5842 * This routine creates a new szarray with \p n elements of type \p eclass.
5845 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5847 MONO_REQ_GC_UNSAFE_MODE;
5850 MonoArray *result = mono_array_new_checked (domain, eclass, n, &error);
5851 mono_error_cleanup (&error);
5856 * mono_array_new_checked:
5857 * \param domain domain where the object is created
5858 * \param eclass element class
5859 * \param n number of array elements
5860 * \param error set on error
5861 * This routine creates a new szarray with \p n elements of type \p eclass.
5862 * On failure returns NULL and sets \p error.
5865 mono_array_new_checked (MonoDomain *domain, MonoClass *eclass, uintptr_t n, MonoError *error)
5871 ac = mono_array_class_get (eclass, 1);
5874 MonoVTable *vtable = mono_class_vtable_full (domain, ac, error);
5875 return_val_if_nok (error, NULL);
5877 return mono_array_new_specific_checked (vtable, n, error);
5881 ves_icall_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5884 MonoArray *arr = mono_array_new_checked (domain, eclass, n, &error);
5885 mono_error_set_pending_exception (&error);
5891 * mono_array_new_specific:
5892 * \param vtable a vtable in the appropriate domain for an initialized class
5893 * \param n number of array elements
5894 * This routine is a fast alternative to \c mono_array_new for code which
5895 * can be sure about the domain it operates in.
5898 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5901 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5902 mono_error_cleanup (&error);
5908 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
5910 MONO_REQ_GC_UNSAFE_MODE;
5917 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
5918 mono_error_set_generic_error (error, "System", "OverflowException", "");
5922 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
5923 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5926 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
5928 if (G_UNLIKELY (!o)) {
5929 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5933 return (MonoArray*)o;
5937 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
5940 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5941 mono_error_set_pending_exception (&error);
5947 * mono_string_empty_wrapper:
5949 * Returns: The same empty string instance as the managed string.Empty
5952 mono_string_empty_wrapper (void)
5954 MonoDomain *domain = mono_domain_get ();
5955 return mono_string_empty (domain);
5959 * mono_string_empty:
5961 * Returns: The same empty string instance as the managed string.Empty
5964 mono_string_empty (MonoDomain *domain)
5967 g_assert (domain->empty_string);
5968 return domain->empty_string;
5972 * mono_string_new_utf16:
5973 * \param text a pointer to an utf16 string
5974 * \param len the length of the string
5975 * \returns A newly created string object which contains \p text.
5978 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
5980 MONO_REQ_GC_UNSAFE_MODE;
5983 MonoString *res = NULL;
5984 res = mono_string_new_utf16_checked (domain, text, len, &error);
5985 mono_error_cleanup (&error);
5991 * mono_string_new_utf16_checked:
5992 * \param text a pointer to an utf16 string
5993 * \param len the length of the string
5994 * \param error written on error.
5995 * \returns A newly created string object which contains \p text.
5996 * On error, returns NULL and sets \p error.
5999 mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
6001 MONO_REQ_GC_UNSAFE_MODE;
6007 s = mono_string_new_size_checked (domain, len, error);
6009 memcpy (mono_string_chars (s), text, len * 2);
6015 * mono_string_new_utf16_handle:
6016 * \param text a pointer to an utf16 string
6017 * \param len the length of the string
6018 * \param error written on error.
6019 * \returns A newly created string object which contains \p text.
6020 * On error, returns NULL and sets \p error.
6023 mono_string_new_utf16_handle (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
6025 return MONO_HANDLE_NEW (MonoString, mono_string_new_utf16_checked (domain, text, len, error));
6029 * mono_string_new_utf32_checked:
6030 * \param text a pointer to an utf32 string
6031 * \param len the length of the string
6032 * \param error set on failure.
6033 * \returns A newly created string object which contains \p text. On failure returns NULL and sets \p error.
6036 mono_string_new_utf32_checked (MonoDomain *domain, const mono_unichar4 *text, gint32 len, MonoError *error)
6038 MONO_REQ_GC_UNSAFE_MODE;
6041 mono_unichar2 *utf16_output = NULL;
6042 gint32 utf16_len = 0;
6043 GError *gerror = NULL;
6044 glong items_written;
6047 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
6050 g_error_free (gerror);
6052 while (utf16_output [utf16_len]) utf16_len++;
6054 s = mono_string_new_size_checked (domain, utf16_len, error);
6055 return_val_if_nok (error, NULL);
6057 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
6059 g_free (utf16_output);
6065 * mono_string_new_utf32:
6066 * \param text a pointer to a UTF-32 string
6067 * \param len the length of the string
6068 * \returns A newly created string object which contains \p text.
6071 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
6074 MonoString *result = mono_string_new_utf32_checked (domain, text, len, &error);
6075 mono_error_cleanup (&error);
6080 * mono_string_new_size:
6081 * \param text a pointer to a UTF-16 string
6082 * \param len the length of the string
6083 * \returns A newly created string object of \p len
6086 mono_string_new_size (MonoDomain *domain, gint32 len)
6089 MonoString *str = mono_string_new_size_checked (domain, len, &error);
6090 mono_error_cleanup (&error);
6096 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
6098 MONO_REQ_GC_UNSAFE_MODE;
6106 /* check for overflow */
6107 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
6108 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
6112 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
6113 g_assert (size > 0);
6115 vtable = mono_class_vtable (domain, mono_defaults.string_class);
6118 s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
6120 if (G_UNLIKELY (!s)) {
6121 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", size);
6129 * mono_string_new_len:
6130 * \param text a pointer to an utf8 string
6131 * \param length number of bytes in \p text to consider
6132 * \returns A newly created string object which contains \p text.
6135 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
6137 MONO_REQ_GC_UNSAFE_MODE;
6140 MonoString *result = mono_string_new_len_checked (domain, text, length, &error);
6141 mono_error_cleanup (&error);
6146 * mono_string_new_len_checked:
6147 * \param text a pointer to an utf8 string
6148 * \param length number of bytes in \p text to consider
6149 * \param error set on error
6150 * \returns A newly created string object which contains \p text. On
6151 * failure returns NULL and sets \p error.
6154 mono_string_new_len_checked (MonoDomain *domain, const char *text, guint length, MonoError *error)
6156 MONO_REQ_GC_UNSAFE_MODE;
6160 GError *eg_error = NULL;
6161 MonoString *o = NULL;
6163 glong items_written;
6165 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
6168 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6170 g_error_free (eg_error);
6179 * \param text a pointer to a UTF-8 string
6180 * \deprecated Use \c mono_string_new_checked in new code.
6181 * This function asserts if it cannot allocate a new string.
6182 * \returns A newly created string object which contains \p text.
6185 mono_string_new (MonoDomain *domain, const char *text)
6188 MonoString *res = NULL;
6189 res = mono_string_new_checked (domain, text, &error);
6190 mono_error_assert_ok (&error);
6195 * mono_string_new_checked:
6196 * \param text a pointer to an utf8 string
6197 * \param merror set on error
6198 * \returns A newly created string object which contains \p text.
6199 * On error returns NULL and sets \p merror.
6202 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
6204 MONO_REQ_GC_UNSAFE_MODE;
6206 GError *eg_error = NULL;
6207 MonoString *o = NULL;
6209 glong items_written;
6216 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &eg_error);
6219 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6221 mono_error_set_execution_engine (error, "String conversion error: %s", eg_error->message);
6226 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
6231 MonoString *o = NULL;
6233 if (!g_utf8_validate (text, -1, &end)) {
6234 mono_error_set_argument (error, "text", "Not a valid utf8 string");
6238 len = g_utf8_strlen (text, -1);
6239 o = mono_string_new_size_checked (domain, len, error);
6242 str = mono_string_chars (o);
6244 while (text < end) {
6245 *str++ = g_utf8_get_char (text);
6246 text = g_utf8_next_char (text);
6255 * mono_string_new_wrapper:
6256 * \param text pointer to UTF-8 characters.
6257 * Helper function to create a string object from \p text in the current domain.
6260 mono_string_new_wrapper (const char *text)
6262 MONO_REQ_GC_UNSAFE_MODE;
6264 MonoDomain *domain = mono_domain_get ();
6268 MonoString *result = mono_string_new_checked (domain, text, &error);
6269 mono_error_assert_ok (&error);
6278 * \param class the class of the value
6279 * \param value a pointer to the unboxed data
6280 * \returns A newly created object which contains \p value.
6283 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
6286 MonoObject *result = mono_value_box_checked (domain, klass, value, &error);
6287 mono_error_cleanup (&error);
6292 * mono_value_box_checked:
6293 * \param domain the domain of the new object
6294 * \param class the class of the value
6295 * \param value a pointer to the unboxed data
6296 * \param error set on error
6297 * \returns A newly created object which contains \p value. On failure
6298 * returns NULL and sets \p error.
6301 mono_value_box_checked (MonoDomain *domain, MonoClass *klass, gpointer value, MonoError *error)
6303 MONO_REQ_GC_UNSAFE_MODE;
6310 g_assert (klass->valuetype);
6311 if (mono_class_is_nullable (klass))
6312 return mono_nullable_box ((guint8 *)value, klass, error);
6314 vtable = mono_class_vtable (domain, klass);
6317 size = mono_class_instance_size (klass);
6318 res = mono_object_new_alloc_specific_checked (vtable, error);
6319 return_val_if_nok (error, NULL);
6321 size = size - sizeof (MonoObject);
6324 g_assert (size == mono_class_value_size (klass, NULL));
6325 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
6327 #if NO_UNALIGNED_ACCESS
6328 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6332 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
6335 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
6338 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
6341 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
6344 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6348 if (klass->has_finalize) {
6349 mono_object_register_finalizer (res);
6350 return_val_if_nok (error, NULL);
6357 * \param dest destination pointer
6358 * \param src source pointer
6359 * \param klass a valuetype class
6360 * Copy a valuetype from \p src to \p dest. This function must be used
6361 * when \p klass contains reference fields.
6364 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
6366 MONO_REQ_GC_UNSAFE_MODE;
6368 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
6372 * mono_value_copy_array:
6373 * \param dest destination array
6374 * \param dest_idx index in the \p dest array
6375 * \param src source pointer
6376 * \param count number of items
6377 * Copy \p count valuetype items from \p src to the array \p dest at index \p dest_idx.
6378 * This function must be used when \p klass contains references fields.
6379 * Overlap is handled.
6382 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
6384 MONO_REQ_GC_UNSAFE_MODE;
6386 int size = mono_array_element_size (dest->obj.vtable->klass);
6387 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
6388 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
6389 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
6393 * mono_object_get_domain:
6394 * \param obj object to query
6395 * \returns the \c MonoDomain where the object is hosted
6398 mono_object_get_domain (MonoObject *obj)
6400 MONO_REQ_GC_UNSAFE_MODE;
6402 return mono_object_domain (obj);
6406 * mono_object_get_class:
6407 * \param obj object to query
6408 * Use this function to obtain the \c MonoClass* for a given \c MonoObject.
6409 * \returns the \c MonoClass of the object.
6412 mono_object_get_class (MonoObject *obj)
6414 MONO_REQ_GC_UNSAFE_MODE;
6416 return mono_object_class (obj);
6419 * mono_object_get_size:
6420 * \param o object to query
6421 * \returns the size, in bytes, of \p o
6424 mono_object_get_size (MonoObject* o)
6426 MONO_REQ_GC_UNSAFE_MODE;
6428 MonoClass* klass = mono_object_class (o);
6429 if (klass == mono_defaults.string_class) {
6430 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
6431 } else if (o->vtable->rank) {
6432 MonoArray *array = (MonoArray*)o;
6433 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
6434 if (array->bounds) {
6437 size += sizeof (MonoArrayBounds) * o->vtable->rank;
6441 return mono_class_instance_size (klass);
6446 * mono_object_unbox:
6447 * \param obj object to unbox
6448 * \returns a pointer to the start of the valuetype boxed in this
6451 * This method will assert if the object passed is not a valuetype.
6454 mono_object_unbox (MonoObject *obj)
6456 MONO_REQ_GC_UNSAFE_MODE;
6458 /* add assert for valuetypes? */
6459 g_assert (obj->vtable->klass->valuetype);
6460 return ((char*)obj) + sizeof (MonoObject);
6464 * mono_object_isinst:
6465 * \param obj an object
6466 * \param klass a pointer to a class
6467 * \returns \p obj if \p obj is derived from \p klass or NULL otherwise.
6470 mono_object_isinst (MonoObject *obj_raw, MonoClass *klass)
6472 MONO_REQ_GC_UNSAFE_MODE;
6474 HANDLE_FUNCTION_ENTER ();
6475 MONO_HANDLE_DCL (MonoObject, obj);
6477 MonoObjectHandle result = mono_object_handle_isinst (obj, klass, &error);
6478 mono_error_cleanup (&error);
6479 HANDLE_FUNCTION_RETURN_OBJ (result);
6484 * mono_object_isinst_checked:
6485 * \param obj an object
6486 * \param klass a pointer to a class
6487 * \param error set on error
6488 * \returns \p obj if \p obj is derived from \p klass or NULL if it isn't.
6489 * On failure returns NULL and sets \p error.
6492 mono_object_isinst_checked (MonoObject *obj_raw, MonoClass *klass, MonoError *error)
6494 MONO_REQ_GC_UNSAFE_MODE;
6496 HANDLE_FUNCTION_ENTER ();
6498 MONO_HANDLE_DCL (MonoObject, obj);
6499 MonoObjectHandle result = mono_object_handle_isinst (obj, klass, error);
6500 HANDLE_FUNCTION_RETURN_OBJ (result);
6504 * mono_object_handle_isinst:
6505 * \param obj an object
6506 * \param klass a pointer to a class
6507 * \param error set on error
6508 * \returns \p obj if \p obj is derived from \p klass or NULL if it isn't.
6509 * On failure returns NULL and sets \p error.
6512 mono_object_handle_isinst (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
6517 mono_class_init (klass);
6519 if (mono_class_is_marshalbyref (klass) || mono_class_is_interface (klass)) {
6520 return mono_object_handle_isinst_mbyref (obj, klass, error);
6523 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6525 if (!MONO_HANDLE_IS_NULL (obj) && mono_class_is_assignable_from (klass, mono_handle_class (obj)))
6526 MONO_HANDLE_ASSIGN (result, obj);
6531 * mono_object_isinst_mbyref:
6534 mono_object_isinst_mbyref (MonoObject *obj_raw, MonoClass *klass)
6536 MONO_REQ_GC_UNSAFE_MODE;
6538 HANDLE_FUNCTION_ENTER ();
6540 MONO_HANDLE_DCL (MonoObject, obj);
6541 MonoObjectHandle result = mono_object_handle_isinst_mbyref (obj, klass, &error);
6542 mono_error_cleanup (&error); /* FIXME better API that doesn't swallow the error */
6543 HANDLE_FUNCTION_RETURN_OBJ (result);
6547 mono_object_handle_isinst_mbyref (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
6551 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6553 if (MONO_HANDLE_IS_NULL (obj))
6556 MonoVTable *vt = MONO_HANDLE_GETVAL (obj, vtable);
6558 if (mono_class_is_interface (klass)) {
6559 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
6560 MONO_HANDLE_ASSIGN (result, obj);
6564 /* casting an array one of the invariant interfaces that must act as such */
6565 if (klass->is_array_special_interface) {
6566 if (mono_class_is_assignable_from (klass, vt->klass)) {
6567 MONO_HANDLE_ASSIGN (result, obj);
6572 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
6573 else if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, mono_handle_class (obj))) {
6574 MONO_HANDLE_ASSIGN (result, obj);
6578 MonoClass *oklass = vt->klass;
6579 if (mono_class_is_transparent_proxy (oklass)){
6580 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), remote_class);
6581 oklass = remote_class->proxy_class;
6584 mono_class_setup_supertypes (klass);
6585 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass)) {
6586 MONO_HANDLE_ASSIGN (result, obj);
6590 #ifndef DISABLE_REMOTING
6591 if (mono_class_is_transparent_proxy (vt->klass))
6593 MonoBoolean custom_type_info = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), custom_type_info);
6594 if (!custom_type_info)
6596 MonoDomain *domain = mono_domain_get ();
6597 MonoObjectHandle rp = MONO_HANDLE_NEW (MonoObject, NULL);
6598 MONO_HANDLE_GET (rp, MONO_HANDLE_CAST (MonoTransparentProxy, obj), rp);
6599 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
6600 MonoMethod *im = NULL;
6603 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
6605 mono_error_set_not_supported (error, "Linked away.");
6608 im = mono_object_handle_get_virtual_method (rp, im, error);
6613 MonoReflectionTypeHandle reftype = mono_type_get_object_handle (domain, &klass->byval_arg, error);
6617 pa [0] = MONO_HANDLE_RAW (reftype);
6618 pa [1] = MONO_HANDLE_RAW (obj);
6619 MonoObject *res = mono_runtime_invoke_checked (im, MONO_HANDLE_RAW (rp), pa, error);
6623 if (*(MonoBoolean *) mono_object_unbox(res)) {
6624 /* Update the vtable of the remote type, so it can safely cast to this new type */
6625 mono_upgrade_remote_class (domain, obj, klass, error);
6628 MONO_HANDLE_ASSIGN (result, obj);
6631 #endif /* DISABLE_REMOTING */
6637 * mono_object_castclass_mbyref:
6638 * \param obj an object
6639 * \param klass a pointer to a class
6640 * \returns \p obj if \p obj is derived from \p klass, returns NULL otherwise.
6643 mono_object_castclass_mbyref (MonoObject *obj_raw, MonoClass *klass)
6645 MONO_REQ_GC_UNSAFE_MODE;
6646 HANDLE_FUNCTION_ENTER ();
6648 MONO_HANDLE_DCL (MonoObject, obj);
6649 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6650 if (MONO_HANDLE_IS_NULL (obj))
6652 MONO_HANDLE_ASSIGN (result, mono_object_handle_isinst_mbyref (obj, klass, &error));
6653 mono_error_cleanup (&error);
6655 HANDLE_FUNCTION_RETURN_OBJ (result);
6659 MonoDomain *orig_domain;
6665 str_lookup (MonoDomain *domain, gpointer user_data)
6667 MONO_REQ_GC_UNSAFE_MODE;
6669 LDStrInfo *info = (LDStrInfo *)user_data;
6670 if (info->res || domain == info->orig_domain)
6672 info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
6676 mono_string_get_pinned (MonoString *str, MonoError *error)
6678 MONO_REQ_GC_UNSAFE_MODE;
6682 /* We only need to make a pinned version of a string if this is a moving GC */
6683 if (!mono_gc_is_moving ())
6687 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
6688 news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
6690 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
6691 news->length = mono_string_length (str);
6693 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6699 mono_string_is_interned_lookup (MonoString *str, int insert, MonoError *error)
6701 MONO_REQ_GC_UNSAFE_MODE;
6703 MonoGHashTable *ldstr_table;
6704 MonoString *s, *res;
6709 domain = ((MonoObject *)str)->vtable->domain;
6710 ldstr_table = domain->ldstr_table;
6712 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6718 /* Allocate outside the lock */
6720 s = mono_string_get_pinned (str, error);
6721 return_val_if_nok (error, NULL);
6724 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6729 mono_g_hash_table_insert (ldstr_table, s, s);
6734 LDStrInfo ldstr_info;
6735 ldstr_info.orig_domain = domain;
6736 ldstr_info.ins = str;
6737 ldstr_info.res = NULL;
6739 mono_domain_foreach (str_lookup, &ldstr_info);
6740 if (ldstr_info.res) {
6742 * the string was already interned in some other domain:
6743 * intern it in the current one as well.
6745 mono_g_hash_table_insert (ldstr_table, str, str);
6755 * mono_string_is_interned:
6756 * \param o String to probe
6757 * \returns Whether the string has been interned.
6760 mono_string_is_interned (MonoString *o)
6763 MonoString *result = mono_string_is_interned_lookup (o, FALSE, &error);
6764 /* This function does not fail. */
6765 mono_error_assert_ok (&error);
6770 * mono_string_intern:
6771 * \param o String to intern
6772 * Interns the string passed.
6773 * \returns The interned string.
6776 mono_string_intern (MonoString *str)
6779 MonoString *result = mono_string_intern_checked (str, &error);
6780 mono_error_assert_ok (&error);
6785 * mono_string_intern_checked:
6786 * \param o String to intern
6787 * \param error set on error.
6788 * Interns the string passed.
6789 * \returns The interned string. On failure returns NULL and sets \p error
6792 mono_string_intern_checked (MonoString *str, MonoError *error)
6794 MONO_REQ_GC_UNSAFE_MODE;
6798 return mono_string_is_interned_lookup (str, TRUE, error);
6803 * \param domain the domain where the string will be used.
6804 * \param image a metadata context
6805 * \param idx index into the user string table.
6806 * Implementation for the \c ldstr opcode.
6807 * \returns a loaded string from the \p image / \p idx combination.
6810 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
6813 MonoString *result = mono_ldstr_checked (domain, image, idx, &error);
6814 mono_error_cleanup (&error);
6819 * mono_ldstr_checked:
6820 * \param domain the domain where the string will be used.
6821 * \param image a metadata context
6822 * \param idx index into the user string table.
6823 * \param error set on error.
6824 * Implementation for the \c ldstr opcode.
6825 * \returns A loaded string from the \p image / \p idx combination.
6826 * On failure returns NULL and sets \p error.
6829 mono_ldstr_checked (MonoDomain *domain, MonoImage *image, guint32 idx, MonoError *error)
6831 MONO_REQ_GC_UNSAFE_MODE;
6834 if (image->dynamic) {
6835 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL, error);
6838 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6839 return NULL; /*FIXME we should probably be raising an exception here*/
6840 MonoString *str = mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx), error);
6846 * mono_ldstr_metadata_sig
6847 * \param domain the domain for the string
6848 * \param sig the signature of a metadata string
6849 * \param error set on error
6850 * \returns a \c MonoString for a string stored in the metadata. On
6851 * failure returns NULL and sets \p error.
6854 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error)
6856 MONO_REQ_GC_UNSAFE_MODE;
6859 const char *str = sig;
6860 MonoString *o, *interned;
6863 len2 = mono_metadata_decode_blob_size (str, &str);
6866 o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, error);
6867 return_val_if_nok (error, NULL);
6868 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
6871 guint16 *p2 = (guint16*)mono_string_chars (o);
6872 for (i = 0; i < len2; ++i) {
6873 *p2 = GUINT16_FROM_LE (*p2);
6879 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6882 return interned; /* o will get garbage collected */
6884 o = mono_string_get_pinned (o, error);
6887 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6889 mono_g_hash_table_insert (domain->ldstr_table, o, o);
6901 * Same as mono_ldstr, but return a NULL terminated utf8 string instead
6905 mono_ldstr_utf8 (MonoImage *image, guint32 idx, MonoError *error)
6911 GError *gerror = NULL;
6915 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6916 return NULL; /*FIXME we should probably be raising an exception here*/
6917 str = mono_metadata_user_string (image, idx);
6919 len2 = mono_metadata_decode_blob_size (str, &str);
6922 as = g_utf16_to_utf8 ((guint16*)str, len2, NULL, &written, &gerror);
6924 mono_error_set_argument (error, "string", "%s", gerror->message);
6925 g_error_free (gerror);
6928 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6929 if (len2 > written) {
6930 /* allocate the total length and copy the part of the string that has been converted */
6931 char *as2 = (char *)g_malloc0 (len2);
6932 memcpy (as2, as, written);
6941 * mono_string_to_utf8:
6942 * \param s a \c System.String
6943 * \deprecated Use \c mono_string_to_utf8_checked to avoid having an exception arbitrarily raised.
6944 * \returns the UTF-8 representation for \p s.
6945 * The resulting buffer needs to be freed with \c mono_free().
6948 mono_string_to_utf8 (MonoString *s)
6950 MONO_REQ_GC_UNSAFE_MODE;
6953 char *result = mono_string_to_utf8_checked (s, &error);
6955 if (!is_ok (&error)) {
6956 mono_error_cleanup (&error);
6963 * mono_string_to_utf8_checked:
6964 * \param s a \c System.String
6965 * \param error a \c MonoError.
6966 * Converts a \c MonoString to its UTF-8 representation. May fail; check
6967 * \p error to determine whether the conversion was successful.
6968 * The resulting buffer should be freed with \c mono_free().
6971 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
6973 MONO_REQ_GC_UNSAFE_MODE;
6977 GError *gerror = NULL;
6985 return g_strdup ("");
6987 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
6989 mono_error_set_argument (error, "string", "%s", gerror->message);
6990 g_error_free (gerror);
6993 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6994 if (s->length > written) {
6995 /* allocate the total length and copy the part of the string that has been converted */
6996 char *as2 = (char *)g_malloc0 (s->length);
6997 memcpy (as2, as, written);
7006 mono_string_handle_to_utf8 (MonoStringHandle s, MonoError *error)
7008 return mono_string_to_utf8_checked (MONO_HANDLE_RAW (s), error);
7012 * mono_string_to_utf8_ignore:
7013 * \param s a MonoString
7014 * Converts a \c MonoString to its UTF-8 representation. Will ignore
7015 * invalid surrogate pairs.
7016 * The resulting buffer should be freed with \c mono_free().
7019 mono_string_to_utf8_ignore (MonoString *s)
7021 MONO_REQ_GC_UNSAFE_MODE;
7030 return g_strdup ("");
7032 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
7034 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
7035 if (s->length > written) {
7036 /* allocate the total length and copy the part of the string that has been converted */
7037 char *as2 = (char *)g_malloc0 (s->length);
7038 memcpy (as2, as, written);
7047 * mono_string_to_utf8_image_ignore:
7048 * \param s a \c System.String
7049 * Same as \c mono_string_to_utf8_ignore, but allocate the string from the image mempool.
7052 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
7054 MONO_REQ_GC_UNSAFE_MODE;
7056 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
7060 * mono_string_to_utf8_mp_ignore:
7061 * \param s a \c System.String
7062 * Same as \c mono_string_to_utf8_ignore, but allocate the string from a mempool.
7065 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
7067 MONO_REQ_GC_UNSAFE_MODE;
7069 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
7074 * mono_string_to_utf16:
7075 * \param s a \c MonoString
7076 * \returns a null-terminated array of the UTF-16 chars
7077 * contained in \p s. The result must be freed with \c g_free().
7078 * This is a temporary helper until our string implementation
7079 * is reworked to always include the null-terminating char.
7082 mono_string_to_utf16 (MonoString *s)
7084 MONO_REQ_GC_UNSAFE_MODE;
7091 as = (char *)g_malloc ((s->length * 2) + 2);
7092 as [(s->length * 2)] = '\0';
7093 as [(s->length * 2) + 1] = '\0';
7096 return (gunichar2 *)(as);
7099 memcpy (as, mono_string_chars(s), s->length * 2);
7100 return (gunichar2 *)(as);
7104 * mono_string_to_utf32:
7105 * \param s a \c MonoString
7106 * \returns a null-terminated array of the UTF-32 (UCS-4) chars
7107 * contained in \p s. The result must be freed with \c g_free().
7110 mono_string_to_utf32 (MonoString *s)
7112 MONO_REQ_GC_UNSAFE_MODE;
7114 mono_unichar4 *utf32_output = NULL;
7115 GError *error = NULL;
7116 glong items_written;
7121 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
7124 g_error_free (error);
7126 return utf32_output;
7130 * mono_string_from_utf16:
7131 * \param data the UTF-16 string (LPWSTR) to convert
7132 * Converts a NULL-terminated UTF-16 string (LPWSTR) to a \c MonoString.
7133 * \returns a \c MonoString.
7136 mono_string_from_utf16 (gunichar2 *data)
7139 MonoString *result = mono_string_from_utf16_checked (data, &error);
7140 mono_error_cleanup (&error);
7145 * mono_string_from_utf16_checked:
7146 * \param data the UTF-16 string (LPWSTR) to convert
7147 * \param error set on error
7148 * Converts a NULL-terminated UTF-16 string (LPWSTR) to a \c MonoString.
7149 * \returns a \c MonoString. On failure sets \p error and returns NULL.
7152 mono_string_from_utf16_checked (gunichar2 *data, MonoError *error)
7155 MONO_REQ_GC_UNSAFE_MODE;
7158 MonoDomain *domain = mono_domain_get ();
7164 while (data [len]) len++;
7166 return mono_string_new_utf16_checked (domain, data, len, error);
7170 * mono_string_from_utf32:
7171 * \param data the UTF-32 string (LPWSTR) to convert
7172 * Converts a UTF-32 (UCS-4) string to a \c MonoString.
7173 * \returns a \c MonoString.
7176 mono_string_from_utf32 (mono_unichar4 *data)
7179 MonoString *result = mono_string_from_utf32_checked (data, &error);
7180 mono_error_cleanup (&error);
7185 * mono_string_from_utf32_checked:
7186 * \param data the UTF-32 string (LPWSTR) to convert
7187 * \param error set on error
7188 * Converts a UTF-32 (UCS-4) string to a \c MonoString.
7189 * \returns a \c MonoString. On failure returns NULL and sets \p error.
7192 mono_string_from_utf32_checked (mono_unichar4 *data, MonoError *error)
7194 MONO_REQ_GC_UNSAFE_MODE;
7197 MonoString* result = NULL;
7198 mono_unichar2 *utf16_output = NULL;
7199 GError *gerror = NULL;
7200 glong items_written;
7206 while (data [len]) len++;
7208 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &gerror);
7211 g_error_free (gerror);
7213 result = mono_string_from_utf16_checked (utf16_output, error);
7214 g_free (utf16_output);
7219 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
7221 MONO_REQ_GC_UNSAFE_MODE;
7228 r = mono_string_to_utf8_ignore (s);
7230 r = mono_string_to_utf8_checked (s, error);
7231 if (!mono_error_ok (error))
7238 len = strlen (r) + 1;
7240 mp_s = (char *)mono_mempool_alloc (mp, len);
7242 mp_s = (char *)mono_image_alloc (image, len);
7244 memcpy (mp_s, r, len);
7252 * mono_string_to_utf8_image:
7253 * \param s a \c System.String
7254 * Same as \c mono_string_to_utf8, but allocate the string from the image mempool.
7257 mono_string_to_utf8_image (MonoImage *image, MonoStringHandle s, MonoError *error)
7259 MONO_REQ_GC_UNSAFE_MODE;
7261 return mono_string_to_utf8_internal (NULL, image, MONO_HANDLE_RAW (s), FALSE, error); /* FIXME pin the string */
7265 * mono_string_to_utf8_mp:
7266 * \param s a \c System.String
7267 * Same as \c mono_string_to_utf8, but allocate the string from a mempool.
7270 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
7272 MONO_REQ_GC_UNSAFE_MODE;
7274 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
7278 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
7281 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
7283 eh_callbacks = *cbs;
7286 MonoRuntimeExceptionHandlingCallbacks *
7287 mono_get_eh_callbacks (void)
7289 return &eh_callbacks;
7293 * mono_raise_exception:
7294 * \param ex exception object
7295 * Signal the runtime that the exception \p ex has been raised in unmanaged code.
7298 mono_raise_exception (MonoException *ex)
7300 MONO_REQ_GC_UNSAFE_MODE;
7303 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
7304 * that will cause gcc to omit the function epilog, causing problems when
7305 * the JIT tries to walk the stack, since the return address on the stack
7306 * will point into the next function in the executable, not this one.
7308 eh_callbacks.mono_raise_exception (ex);
7312 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
7314 MONO_REQ_GC_UNSAFE_MODE;
7316 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
7320 * mono_wait_handle_new:
7321 * \param domain Domain where the object will be created
7322 * \param handle Handle for the wait handle
7323 * \param error set on error.
7324 * \returns A new \c MonoWaitHandle created in the given domain for the
7325 * given handle. On failure returns NULL and sets \p error.
7328 mono_wait_handle_new (MonoDomain *domain, HANDLE handle, MonoError *error)
7330 MONO_REQ_GC_UNSAFE_MODE;
7332 MonoWaitHandle *res;
7333 gpointer params [1];
7334 static MonoMethod *handle_set;
7337 res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, error);
7338 return_val_if_nok (error, NULL);
7340 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
7342 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
7344 params [0] = &handle;
7346 mono_runtime_invoke_checked (handle_set, res, params, error);
7351 mono_wait_handle_get_handle (MonoWaitHandle *handle)
7353 MONO_REQ_GC_UNSAFE_MODE;
7355 static MonoClassField *f_safe_handle = NULL;
7358 if (!f_safe_handle) {
7359 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safeWaitHandle");
7360 g_assert (f_safe_handle);
7363 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
7369 mono_runtime_capture_context (MonoDomain *domain, MonoError *error)
7371 MONO_REQ_GC_UNSAFE_MODE;
7373 RuntimeInvokeFunction runtime_invoke;
7377 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
7378 MonoMethod *method = mono_get_context_capture_method ();
7379 MonoMethod *wrapper;
7382 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
7383 domain->capture_context_runtime_invoke = mono_compile_method_checked (wrapper, error);
7384 return_val_if_nok (error, NULL);
7385 domain->capture_context_method = mono_compile_method_checked (method, error);
7386 return_val_if_nok (error, NULL);
7389 runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
7391 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
7394 * mono_async_result_new:
7395 * \param domain domain where the object will be created.
7396 * \param handle wait handle.
7397 * \param state state to pass to AsyncResult
7398 * \param data C closure data.
7399 * \param error set on error.
7400 * Creates a new MonoAsyncResult (\c AsyncResult C# class) in the given domain.
7401 * If the handle is not null, the handle is initialized to a \c MonoWaitHandle.
7402 * On failure returns NULL and sets \p error.
7405 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data, MonoError *error)
7407 MONO_REQ_GC_UNSAFE_MODE;
7410 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, error);
7411 return_val_if_nok (error, NULL);
7412 MonoObject *context = mono_runtime_capture_context (domain, error);
7413 return_val_if_nok (error, NULL);
7414 /* we must capture the execution context from the original thread */
7416 MONO_OBJECT_SETREF (res, execution_context, context);
7417 /* note: result may be null if the flow is suppressed */
7420 res->data = (void **)data;
7421 MONO_OBJECT_SETREF (res, object_data, object_data);
7422 MONO_OBJECT_SETREF (res, async_state, state);
7423 MonoWaitHandle *wait_handle = mono_wait_handle_new (domain, handle, error);
7424 return_val_if_nok (error, NULL);
7426 MONO_OBJECT_SETREF (res, handle, (MonoObject *) wait_handle);
7428 res->sync_completed = FALSE;
7429 res->completed = FALSE;
7435 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
7437 MONO_REQ_GC_UNSAFE_MODE;
7444 g_assert (ares->async_delegate);
7446 ac = (MonoAsyncCall*) ares->object_data;
7448 res = mono_runtime_delegate_invoke_checked (ares->async_delegate, (void**) &ares->async_state, &error);
7449 if (mono_error_set_pending_exception (&error))
7452 gpointer wait_event = NULL;
7454 ac->msg->exc = NULL;
7456 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args, &error);
7458 /* The exit side of the invoke must not be aborted as it would leave the runtime in an undefined state */
7459 mono_threads_begin_abort_protected_block ();
7461 if (!ac->msg->exc) {
7462 MonoException *ex = mono_error_convert_to_exception (&error);
7463 ac->msg->exc = (MonoObject *)ex;
7465 mono_error_cleanup (&error);
7468 MONO_OBJECT_SETREF (ac, res, res);
7470 mono_monitor_enter ((MonoObject*) ares);
7471 ares->completed = 1;
7473 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
7474 mono_monitor_exit ((MonoObject*) ares);
7476 if (wait_event != NULL)
7477 mono_w32event_set (wait_event);
7479 error_init (&error); //the else branch would leave it in an undefined state
7481 mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
7483 mono_threads_end_abort_protected_block ();
7485 if (mono_error_set_pending_exception (&error))
7493 mono_message_init (MonoDomain *domain,
7494 MonoMethodMessage *this_obj,
7495 MonoReflectionMethod *method,
7496 MonoArray *out_args,
7499 MONO_REQ_GC_UNSAFE_MODE;
7501 static MonoMethod *init_message_method = NULL;
7503 if (!init_message_method) {
7504 init_message_method = mono_class_get_method_from_name (mono_defaults.mono_method_message_class, "InitMessage", 2);
7505 g_assert (init_message_method != NULL);
7509 /* FIXME set domain instead? */
7510 g_assert (domain == mono_domain_get ());
7517 mono_runtime_invoke_checked (init_message_method, this_obj, args, error);
7518 return is_ok (error);
7521 #ifndef DISABLE_REMOTING
7523 * mono_remoting_invoke:
7524 * \param real_proxy pointer to a \c RealProxy object
7525 * \param msg The \c MonoMethodMessage to execute
7526 * \param exc used to store exceptions
7527 * \param out_args used to store output arguments
7528 * This is used to call \c RealProxy::Invoke(). \c RealProxy::Invoke() returns an
7529 * \c IMessage interface and it is not trivial to extract results from there. So
7530 * we call an helper method \c PrivateInvoke instead of calling
7531 * \c RealProxy::Invoke() directly.
7532 * \returns the result object.
7535 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, MonoObject **exc, MonoArray **out_args, MonoError *error)
7537 MONO_REQ_GC_UNSAFE_MODE;
7540 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
7547 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
7550 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
7552 mono_error_set_not_supported (error, "Linked away.");
7555 real_proxy->vtable->domain->private_invoke_method = im;
7558 pa [0] = real_proxy;
7563 o = mono_runtime_try_invoke (im, NULL, pa, exc, error);
7564 return_val_if_nok (error, NULL);
7571 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
7572 MonoObject **exc, MonoArray **out_args, MonoError *error)
7574 MONO_REQ_GC_UNSAFE_MODE;
7576 static MonoClass *object_array_klass;
7581 MonoMethodSignature *sig;
7583 int i, j, outarg_count = 0;
7585 #ifndef DISABLE_REMOTING
7586 if (target && mono_object_is_transparent_proxy (target)) {
7587 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
7588 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7589 target = tp->rp->unwrapped_server;
7591 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args, error);
7596 domain = mono_domain_get ();
7597 method = msg->method->method;
7598 sig = mono_method_signature (method);
7600 for (i = 0; i < sig->param_count; i++) {
7601 if (sig->params [i]->byref)
7605 if (!object_array_klass) {
7608 klass = mono_array_class_get (mono_defaults.object_class, 1);
7611 mono_memory_barrier ();
7612 object_array_klass = klass;
7615 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, error);
7616 return_val_if_nok (error, NULL);
7618 mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
7621 MonoObject *ret = mono_runtime_try_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc, error);
7622 return_val_if_nok (error, NULL);
7624 for (i = 0, j = 0; i < sig->param_count; i++) {
7625 if (sig->params [i]->byref) {
7627 arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
7628 mono_array_setref (*out_args, j, arg);
7637 * prepare_to_string_method:
7639 * @target: Set to @obj or unboxed value if a valuetype
7641 * Returns: the ToString override for @obj. If @obj is a valuetype, @target is unboxed otherwise it's @obj.
7644 prepare_to_string_method (MonoObject *obj, void **target)
7646 MONO_REQ_GC_UNSAFE_MODE;
7648 static MonoMethod *to_string = NULL;
7656 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
7658 method = mono_object_get_virtual_method (obj, to_string);
7660 // Unbox value type if needed
7661 if (mono_class_is_valuetype (mono_method_get_class (method))) {
7662 *target = mono_object_unbox (obj);
7668 * mono_object_to_string:
7669 * \param obj The object
7670 * \param exc Any exception thrown by \c ToString. May be NULL.
7671 * \returns the result of calling \c ToString on an object.
7674 mono_object_to_string (MonoObject *obj, MonoObject **exc)
7677 MonoString *s = NULL;
7679 MonoMethod *method = prepare_to_string_method (obj, &target);
7681 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
7682 if (*exc == NULL && !mono_error_ok (&error))
7683 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
7685 mono_error_cleanup (&error);
7687 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
7688 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
7695 * mono_object_to_string_checked:
7696 * \param obj The object
7697 * \param error Set on error.
7698 * \returns the result of calling \c ToString() on an object. If the
7699 * method cannot be invoked or if it raises an exception, sets \p error
7703 mono_object_to_string_checked (MonoObject *obj, MonoError *error)
7707 MonoMethod *method = prepare_to_string_method (obj, &target);
7708 return (MonoString*) mono_runtime_invoke_checked (method, target, NULL, error);
7712 * mono_object_try_to_string:
7713 * \param obj The object
7714 * \param exc Any exception thrown by \c ToString(). Must not be NULL.
7715 * \param error Set if method cannot be invoked.
7716 * \returns the result of calling \c ToString() on an object. If the
7717 * method cannot be invoked sets \p error, if it raises an exception sets \p exc,
7721 mono_object_try_to_string (MonoObject *obj, MonoObject **exc, MonoError *error)
7726 MonoMethod *method = prepare_to_string_method (obj, &target);
7727 return (MonoString*) mono_runtime_try_invoke (method, target, NULL, exc, error);
7733 get_native_backtrace (MonoException *exc_raw)
7735 HANDLE_FUNCTION_ENTER ();
7736 MONO_HANDLE_DCL(MonoException, exc);
7737 char * trace = mono_exception_handle_get_native_backtrace (exc);
7738 HANDLE_FUNCTION_RETURN_VAL (trace);
7742 * mono_print_unhandled_exception:
7743 * \param exc The exception
7744 * Prints the unhandled exception.
7747 mono_print_unhandled_exception (MonoObject *exc)
7749 MONO_REQ_GC_UNSAFE_MODE;
7752 char *message = (char*)"";
7753 gboolean free_message = FALSE;
7756 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
7757 message = g_strdup ("OutOfMemoryException");
7758 free_message = TRUE;
7759 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
7760 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
7761 free_message = TRUE;
7764 if (((MonoException*)exc)->native_trace_ips) {
7765 message = get_native_backtrace ((MonoException*)exc);
7766 free_message = TRUE;
7768 MonoObject *other_exc = NULL;
7769 str = mono_object_try_to_string (exc, &other_exc, &error);
7770 if (other_exc == NULL && !is_ok (&error))
7771 other_exc = (MonoObject*)mono_error_convert_to_exception (&error);
7773 mono_error_cleanup (&error);
7775 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
7776 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
7778 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
7779 original_backtrace, nested_backtrace);
7781 g_free (original_backtrace);
7782 g_free (nested_backtrace);
7783 free_message = TRUE;
7785 message = mono_string_to_utf8_checked (str, &error);
7786 if (!mono_error_ok (&error)) {
7787 mono_error_cleanup (&error);
7788 message = (char *) "";
7790 free_message = TRUE;
7797 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
7798 * exc->vtable->klass->name, message);
7800 g_printerr ("\nUnhandled Exception:\n%s\n", message);
7807 mono_delegate_ctor_with_method_fixme (MonoObject *this_obj_raw, MonoObject *target_raw, gpointer addr, MonoMethod *method, MonoError *error)
7809 HANDLE_FUNCTION_ENTER ();
7811 MONO_HANDLE_DCL (MonoObject, this_obj);
7812 MONO_HANDLE_DCL (MonoObject, target);
7813 gboolean res = mono_delegate_ctor_with_method (this_obj, target, addr, method, error);
7814 HANDLE_FUNCTION_RETURN_VAL (res);
7818 * mono_delegate_ctor_with_method:
7819 * \param this pointer to an uninitialized delegate object
7820 * \param target target object
7821 * \param addr pointer to native code
7822 * \param method method
7823 * \param error set on error.
7824 * Initialize a delegate and sets a specific method, not the one
7825 * associated with \p addr. This is useful when sharing generic code.
7826 * In that case \p addr will most probably not be associated with the
7827 * correct instantiation of the method.
7828 * On failure returns FALSE and sets \p error.
7831 mono_delegate_ctor_with_method (MonoObjectHandle this_obj, MonoObjectHandle target, gpointer addr, MonoMethod *method, MonoError *error)
7833 MONO_REQ_GC_UNSAFE_MODE;
7836 MonoDelegateHandle delegate = MONO_HANDLE_CAST (MonoDelegate, this_obj);
7838 g_assert (!MONO_HANDLE_IS_NULL (this_obj));
7841 MonoClass *klass = mono_handle_class (this_obj);
7842 g_assert (mono_class_has_parent (klass, mono_defaults.multicastdelegate_class));
7845 MONO_HANDLE_SETVAL (delegate, method, MonoMethod*, method);
7847 mono_stats.delegate_creations++;
7849 #ifndef DISABLE_REMOTING
7850 if (!MONO_HANDLE_IS_NULL (target) && mono_class_is_transparent_proxy (mono_handle_class (target))) {
7852 method = mono_marshal_get_remoting_invoke (method);
7853 #ifdef ENABLE_INTERPRETER
7854 //g_error ("need RuntimeMethod in method_ptr when using interpreter");
7856 MONO_HANDLE_SETVAL (delegate, method_ptr, gpointer, mono_compile_method_checked (method, error));
7857 return_val_if_nok (error, FALSE);
7858 MONO_HANDLE_SET (delegate, target, target);
7862 MONO_HANDLE_SETVAL (delegate, method_ptr, gpointer, addr);
7863 MONO_HANDLE_SET (delegate, target, target);
7866 MONO_HANDLE_SETVAL (delegate, invoke_impl, gpointer, callbacks.create_delegate_trampoline (MONO_HANDLE_DOMAIN (delegate), mono_handle_class (delegate)));
7867 if (callbacks.init_delegate)
7868 callbacks.init_delegate (MONO_HANDLE_RAW (delegate)); /* FIXME: update init_delegate callback to take a MonoDelegateHandle */
7873 * mono_delegate_ctor:
7874 * \param this pointer to an uninitialized delegate object
7875 * \param target target object
7876 * \param addr pointer to native code
7877 * \param error set on error.
7878 * This is used to initialize a delegate.
7879 * On failure returns FALSE and sets \p error.
7882 mono_delegate_ctor (MonoObjectHandle this_obj, MonoObjectHandle target, gpointer addr, MonoError *error)
7884 MONO_REQ_GC_UNSAFE_MODE;
7887 MonoDomain *domain = mono_domain_get ();
7889 MonoMethod *method = NULL;
7893 ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
7895 if (!ji && domain != mono_get_root_domain ())
7896 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
7898 method = mono_jit_info_get_method (ji);
7899 g_assert (!mono_class_is_gtd (method->klass));
7902 return mono_delegate_ctor_with_method (this_obj, target, addr, method, error);
7906 * mono_method_call_message_new:
7907 * \param method method to encapsulate
7908 * \param params parameters to the method
7909 * \param invoke optional, delegate invoke.
7910 * \param cb async callback delegate.
7911 * \param state state passed to the async callback.
7912 * \param error set on error.
7913 * Translates arguments pointers into a \c MonoMethodMessage.
7914 * On failure returns NULL and sets \p error.
7917 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
7918 MonoDelegate **cb, MonoObject **state, MonoError *error)
7920 MONO_REQ_GC_UNSAFE_MODE;
7924 MonoDomain *domain = mono_domain_get ();
7925 MonoMethodSignature *sig = mono_method_signature (method);
7926 MonoMethodMessage *msg;
7929 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
7930 return_val_if_nok (error, NULL);
7933 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, error);
7934 return_val_if_nok (error, NULL);
7935 mono_message_init (domain, msg, rm, NULL, error);
7936 return_val_if_nok (error, NULL);
7937 count = sig->param_count - 2;
7939 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
7940 return_val_if_nok (error, NULL);
7941 mono_message_init (domain, msg, rm, NULL, error);
7942 return_val_if_nok (error, NULL);
7943 count = sig->param_count;
7946 for (i = 0; i < count; i++) {
7951 if (sig->params [i]->byref)
7952 vpos = *((gpointer *)params [i]);
7956 klass = mono_class_from_mono_type (sig->params [i]);
7958 if (klass->valuetype) {
7959 arg = mono_value_box_checked (domain, klass, vpos, error);
7960 return_val_if_nok (error, NULL);
7962 arg = *((MonoObject **)vpos);
7964 mono_array_setref (msg->args, i, arg);
7967 if (cb != NULL && state != NULL) {
7968 *cb = *((MonoDelegate **)params [i]);
7970 *state = *((MonoObject **)params [i]);
7977 * mono_method_return_message_restore:
7979 * Restore results from message based processing back to arguments pointers
7982 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args, MonoError *error)
7984 MONO_REQ_GC_UNSAFE_MODE;
7988 MonoMethodSignature *sig = mono_method_signature (method);
7989 int i, j, type, size, out_len;
7991 if (out_args == NULL)
7993 out_len = mono_array_length (out_args);
7997 for (i = 0, j = 0; i < sig->param_count; i++) {
7998 MonoType *pt = sig->params [i];
8003 mono_error_set_execution_engine (error, "The proxy call returned an incorrect number of output arguments");
8007 arg = (char *)mono_array_get (out_args, gpointer, j);
8010 g_assert (type != MONO_TYPE_VOID);
8012 if (MONO_TYPE_IS_REFERENCE (pt)) {
8013 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
8016 MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
8017 size = mono_class_value_size (klass, NULL);
8018 if (klass->has_references)
8019 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
8021 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
8023 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
8024 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
8033 #ifndef DISABLE_REMOTING
8036 * mono_load_remote_field:
8037 * \param this pointer to an object
8038 * \param klass klass of the object containing \p field
8039 * \param field the field to load
8040 * \param res a storage to store the result
8041 * This method is called by the runtime on attempts to load fields of
8042 * transparent proxy objects. \p this points to such TP, \p klass is the class of
8043 * the object containing \p field. \p res is a storage location which can be
8044 * used to store the result.
8045 * \returns an address pointing to the value of field.
8048 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
8051 gpointer result = mono_load_remote_field_checked (this_obj, klass, field, res, &error);
8052 mono_error_cleanup (&error);
8057 * mono_load_remote_field_checked:
8058 * \param this pointer to an object
8059 * \param klass klass of the object containing \p field
8060 * \param field the field to load
8061 * \param res a storage to store the result
8062 * \param error set on error
8063 * This method is called by the runtime on attempts to load fields of
8064 * transparent proxy objects. \p this points to such TP, \p klass is the class of
8065 * the object containing \p field. \p res is a storage location which can be
8066 * used to store the result.
8067 * \returns an address pointing to the value of field. On failure returns NULL and sets \p error.
8070 mono_load_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res, MonoError *error)
8072 MONO_REQ_GC_UNSAFE_MODE;
8074 static MonoMethod *getter = NULL;
8078 MonoDomain *domain = mono_domain_get ();
8079 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8080 MonoClass *field_class;
8081 MonoMethodMessage *msg;
8082 MonoArray *out_args;
8086 g_assert (mono_object_is_transparent_proxy (this_obj));
8087 g_assert (res != NULL);
8089 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8090 mono_field_get_value (tp->rp->unwrapped_server, field, res);
8095 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
8097 mono_error_set_not_supported (error, "Linked away.");
8102 field_class = mono_class_from_mono_type (field->type);
8104 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8105 return_val_if_nok (error, NULL);
8106 out_args = mono_array_new_checked (domain, mono_defaults.object_class, 1, error);
8107 return_val_if_nok (error, NULL);
8108 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, error);
8109 return_val_if_nok (error, NULL);
8110 mono_message_init (domain, msg, rm, out_args, error);
8111 return_val_if_nok (error, NULL);
8113 full_name = mono_type_get_full_name (klass);
8114 MonoString *full_name_str = mono_string_new_checked (domain, full_name, error);
8116 return_val_if_nok (error, NULL);
8117 mono_array_setref (msg->args, 0, full_name_str);
8118 MonoString *field_name = mono_string_new_checked (domain, mono_field_get_name (field), error);
8119 return_val_if_nok (error, NULL);
8120 mono_array_setref (msg->args, 1, field_name);
8122 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8123 return_val_if_nok (error, NULL);
8126 mono_error_set_exception_instance (error, (MonoException *)exc);
8130 if (mono_array_length (out_args) == 0)
8133 mono_gc_wbarrier_generic_store (res, mono_array_get (out_args, MonoObject *, 0));
8135 if (field_class->valuetype) {
8136 return ((char *)*res) + sizeof (MonoObject);
8142 * mono_load_remote_field_new:
8146 * Missing documentation.
8149 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
8153 MonoObject *result = mono_load_remote_field_new_checked (this_obj, klass, field, &error);
8154 mono_error_cleanup (&error);
8159 * mono_load_remote_field_new_checked:
8160 * \param this pointer to an object
8161 * \param klass klass of the object containing \p field
8162 * \param field the field to load
8163 * \param error set on error.
8164 * This method is called by the runtime on attempts to load fields of
8165 * transparent proxy objects. \p this points to such TP, \p klass is the class of
8166 * the object containing \p field.
8167 * \returns a freshly allocated object containing the value of the field. On failure returns NULL and sets \p error.
8170 mono_load_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoError *error)
8172 MONO_REQ_GC_UNSAFE_MODE;
8176 static MonoMethod *tp_load = NULL;
8178 g_assert (mono_object_is_transparent_proxy (this_obj));
8181 tp_load = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "LoadRemoteFieldNew", -1);
8183 mono_error_set_not_supported (error, "Linked away.");
8188 /* MonoType *type = mono_class_get_type (klass); */
8194 return mono_runtime_invoke_checked (tp_load, this_obj, args, error);
8198 * mono_store_remote_field:
8199 * \param this_obj pointer to an object
8200 * \param klass klass of the object containing \p field
8201 * \param field the field to load
8202 * \param val the value/object to store
8203 * This method is called by the runtime on attempts to store fields of
8204 * transparent proxy objects. \p this_obj points to such TP, \p klass is the class of
8205 * the object containing \p field. \p val is the new value to store in \p field.
8208 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
8211 (void) mono_store_remote_field_checked (this_obj, klass, field, val, &error);
8212 mono_error_cleanup (&error);
8216 * mono_store_remote_field_checked:
8217 * \param this_obj pointer to an object
8218 * \param klass klass of the object containing \p field
8219 * \param field the field to load
8220 * \param val the value/object to store
8221 * \param error set on error
8222 * This method is called by the runtime on attempts to store fields of
8223 * transparent proxy objects. \p this_obj points to such TP, \p klass is the class of
8224 * the object containing \p field. \p val is the new value to store in \p field.
8225 * \returns on success returns TRUE, on failure returns FALSE and sets \p error.
8228 mono_store_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val, MonoError *error)
8231 MONO_REQ_GC_UNSAFE_MODE;
8235 MonoDomain *domain = mono_domain_get ();
8236 MonoClass *field_class;
8239 g_assert (mono_object_is_transparent_proxy (this_obj));
8241 field_class = mono_class_from_mono_type (field->type);
8243 if (field_class->valuetype) {
8244 arg = mono_value_box_checked (domain, field_class, val, error);
8245 return_val_if_nok (error, FALSE);
8247 arg = *((MonoObject**)val);
8250 return mono_store_remote_field_new_checked (this_obj, klass, field, arg, error);
8254 * mono_store_remote_field_new:
8259 * Missing documentation
8262 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
8265 (void) mono_store_remote_field_new_checked (this_obj, klass, field, arg, &error);
8266 mono_error_cleanup (&error);
8270 * mono_store_remote_field_new_checked:
8276 * Missing documentation
8279 mono_store_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg, MonoError *error)
8281 MONO_REQ_GC_UNSAFE_MODE;
8283 static MonoMethod *tp_store = NULL;
8287 g_assert (mono_object_is_transparent_proxy (this_obj));
8290 tp_store = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "StoreRemoteField", -1);
8292 mono_error_set_not_supported (error, "Linked away.");
8302 mono_runtime_invoke_checked (tp_store, this_obj, args, error);
8303 return is_ok (error);
8308 * mono_create_ftnptr:
8310 * Given a function address, create a function descriptor for it.
8311 * This is only needed on some platforms.
8314 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
8316 return callbacks.create_ftnptr (domain, addr);
8320 * mono_get_addr_from_ftnptr:
8322 * Given a pointer to a function descriptor, return the function address.
8323 * This is only needed on some platforms.
8326 mono_get_addr_from_ftnptr (gpointer descr)
8328 return callbacks.get_addr_from_ftnptr (descr);
8332 * mono_string_chars:
8333 * \param s a \c MonoString
8334 * \returns a pointer to the UTF-16 characters stored in the \c MonoString
8337 mono_string_chars (MonoString *s)
8339 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
8345 * mono_string_length:
8346 * \param s MonoString
8347 * \returns the length in characters of the string
8350 mono_string_length (MonoString *s)
8352 MONO_REQ_GC_UNSAFE_MODE;
8358 * mono_string_handle_length:
8359 * \param s \c MonoString
8360 * \returns the length in characters of the string
8363 mono_string_handle_length (MonoStringHandle s)
8365 MONO_REQ_GC_UNSAFE_MODE;
8367 return MONO_HANDLE_GETVAL (s, length);
8372 * mono_array_length:
8373 * \param array a \c MonoArray*
8374 * \returns the total number of elements in the array. This works for
8375 * both vectors and multidimensional arrays.
8378 mono_array_length (MonoArray *array)
8380 MONO_REQ_GC_UNSAFE_MODE;
8382 return array->max_length;
8386 * mono_array_addr_with_size:
8387 * \param array a \c MonoArray*
8388 * \param size size of the array elements
8389 * \param idx index into the array
8390 * Use this function to obtain the address for the \p idx item on the
8391 * \p array containing elements of size \p size.
8393 * This method performs no bounds checking or type checking.
8394 * \returns the address of the \p idx element in the array.
8397 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
8399 MONO_REQ_GC_UNSAFE_MODE;
8401 return ((char*)(array)->vector) + size * idx;
8406 mono_glist_to_array (GList *list, MonoClass *eclass, MonoError *error)
8408 MonoDomain *domain = mono_domain_get ();
8416 len = g_list_length (list);
8417 res = mono_array_new_checked (domain, eclass, len, error);
8418 return_val_if_nok (error, NULL);
8420 for (i = 0; list; list = list->next, i++)
8421 mono_array_set (res, gpointer, i, list->data);
8428 * The following section is purely to declare prototypes and
8429 * document the API, as these C files are processed by our
8435 * \param array array to alter
8436 * \param element_type A C type name, this macro will use the sizeof(type) to determine the element size
8437 * \param index index into the array
8438 * \param value value to set
8439 * Value Type version: This sets the \p index's element of the \p array
8440 * with elements of size sizeof(type) to the provided \p value.
8442 * This macro does not attempt to perform type checking or bounds checking.
8444 * Use this to set value types in a \c MonoArray.
8446 void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
8451 * mono_array_setref:
8452 * \param array array to alter
8453 * \param index index into the array
8454 * \param value value to set
8455 * Reference Type version. This sets the \p index's element of the
8456 * \p array with elements of size sizeof(type) to the provided \p value.
8458 * This macro does not attempt to perform type checking or bounds checking.
8460 * Use this to reference types in a \c MonoArray.
8462 void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
8468 * \param array array on which to operate on
8469 * \param element_type C element type (example: \c MonoString*, \c int, \c MonoObject*)
8470 * \param index index into the array
8472 * Use this macro to retrieve the \p index element of an \p array and
8473 * extract the value assuming that the elements of the array match
8474 * the provided type value.
8476 * This method can be used with both arrays holding value types and
8477 * reference types. For reference types, the \p type parameter should
8478 * be a \c MonoObject* or any subclass of it, like \c MonoString*.
8480 * This macro does not attempt to perform type checking or bounds checking.
8482 * \returns The element at the \p index position in the \p array.
8484 Type mono_array_get (MonoArray *array, Type element_type, uintptr_t index)