2 * object.c: Object creation for the Mono runtime
5 * Miguel de Icaza (miguel@ximian.com)
6 * Paolo Molaro (lupus@ximian.com)
8 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
9 * Copyright 2004-2011 Novell, Inc (http://www.novell.com)
10 * Copyright 2001 Xamarin Inc (http://www.xamarin.com)
11 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
20 #include <mono/metadata/mono-endian.h>
21 #include <mono/metadata/tabledefs.h>
22 #include <mono/metadata/tokentype.h>
23 #include <mono/metadata/loader.h>
24 #include <mono/metadata/object.h>
25 #include <mono/metadata/gc-internals.h>
26 #include <mono/metadata/exception.h>
27 #include <mono/metadata/exception-internals.h>
28 #include <mono/metadata/domain-internals.h>
29 #include "mono/metadata/metadata-internals.h"
30 #include "mono/metadata/class-internals.h"
31 #include <mono/metadata/assembly.h>
32 #include <mono/metadata/marshal.h>
33 #include "mono/metadata/debug-helpers.h"
34 #include <mono/metadata/threads.h>
35 #include <mono/metadata/threads-types.h>
36 #include <mono/metadata/environment.h>
37 #include "mono/metadata/profiler-private.h"
38 #include "mono/metadata/security-manager.h"
39 #include <mono/metadata/verify-internals.h>
40 #include <mono/metadata/reflection-internals.h>
41 #include <mono/metadata/w32event.h>
42 #include <mono/utils/strenc.h>
43 #include <mono/utils/mono-counters.h>
44 #include <mono/utils/mono-error-internals.h>
45 #include <mono/utils/mono-memory-model.h>
46 #include <mono/utils/checked-build.h>
47 #include <mono/utils/mono-threads.h>
48 #include <mono/utils/mono-threads-coop.h>
49 #include "cominterop.h"
50 #include <mono/utils/w32api.h>
53 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error);
56 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error);
59 free_main_args (void);
62 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error);
65 array_full_copy_unchecked_size (MonoArray *src, MonoArray *dest, MonoClass *klass, uintptr_t size);
68 class_get_virtual_method (MonoClass *klass, MonoMethod *method, gboolean is_proxy, MonoError *error);
70 /* Class lazy loading functions */
71 static GENERATE_GET_CLASS_WITH_CACHE (pointer, "System.Reflection", "Pointer")
72 static GENERATE_GET_CLASS_WITH_CACHE (remoting_services, "System.Runtime.Remoting", "RemotingServices")
73 static GENERATE_GET_CLASS_WITH_CACHE (unhandled_exception_event_args, "System", "UnhandledExceptionEventArgs")
74 static GENERATE_GET_CLASS_WITH_CACHE (sta_thread_attribute, "System", "STAThreadAttribute")
75 static GENERATE_GET_CLASS_WITH_CACHE (activation_services, "System.Runtime.Remoting.Activation", "ActivationServices")
78 #define ldstr_lock() mono_os_mutex_lock (&ldstr_section)
79 #define ldstr_unlock() mono_os_mutex_unlock (&ldstr_section)
80 static mono_mutex_t ldstr_section;
84 * mono_runtime_object_init:
85 * @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 * @this_obj: the object to initialize
101 * @error: set on error.
103 * This function calls the zero-argument constructor (which must
104 * exist) for the given object and returns TRUE on success, or FALSE
105 * on error and sets @error.
108 mono_runtime_object_init_checked (MonoObject *this_obj, MonoError *error)
110 MONO_REQ_GC_UNSAFE_MODE;
112 MonoMethod *method = NULL;
113 MonoClass *klass = this_obj->vtable->klass;
116 method = mono_class_get_method_from_name (klass, ".ctor", 0);
118 g_error ("Could not lookup zero argument constructor for class %s", mono_type_get_full_name (klass));
120 if (method->klass->valuetype)
121 this_obj = (MonoObject *)mono_object_unbox (this_obj);
123 mono_runtime_invoke_checked (method, this_obj, NULL, error);
124 return is_ok (error);
127 /* The pseudo algorithm for type initialization from the spec
128 Note it doesn't say anything about domains - only threads.
130 2. If the type is initialized you are done.
131 2.1. If the type is not yet initialized, try to take an
133 2.2. If successful, record this thread as responsible for
134 initializing the type and proceed to step 2.3.
135 2.2.1. If not, see whether this thread or any thread
136 waiting for this thread to complete already holds the lock.
137 2.2.2. If so, return since blocking would create a deadlock. This thread
138 will now see an incompletely initialized state for the type,
139 but no deadlock will arise.
140 2.2.3 If not, block until the type is initialized then return.
141 2.3 Initialize the parent type and then all interfaces implemented
143 2.4 Execute the type initialization code for this type.
144 2.5 Mark the type as initialized, release the initialization lock,
145 awaken any threads waiting for this type to be initialized,
152 MonoNativeThreadId initializing_tid;
153 guint32 waiting_count;
156 /* condvar used to wait for 'done' becoming TRUE */
158 } TypeInitializationLock;
160 /* for locking access to type_initialization_hash and blocked_thread_hash */
161 static MonoCoopMutex type_initialization_section;
164 mono_type_initialization_lock (void)
166 /* The critical sections protected by this lock in mono_runtime_class_init_full () can block */
167 mono_coop_mutex_lock (&type_initialization_section);
171 mono_type_initialization_unlock (void)
173 mono_coop_mutex_unlock (&type_initialization_section);
177 mono_type_init_lock (TypeInitializationLock *lock)
179 MONO_REQ_GC_NEUTRAL_MODE;
181 mono_coop_mutex_lock (&lock->mutex);
185 mono_type_init_unlock (TypeInitializationLock *lock)
187 mono_coop_mutex_unlock (&lock->mutex);
190 /* from vtable to lock */
191 static GHashTable *type_initialization_hash;
193 /* from thread id to thread id being waited on */
194 static GHashTable *blocked_thread_hash;
197 static MonoThread *main_thread;
199 /* Functions supplied by the runtime */
200 static MonoRuntimeCallbacks callbacks;
203 * mono_thread_set_main:
204 * @thread: thread to set as the main thread
206 * This function can be used to instruct the runtime to treat @thread
207 * as the main thread, ie, the thread that would normally execute the Main()
208 * method. This basically means that at the end of @thread, the runtime will
209 * wait for the existing foreground threads to quit and other such details.
212 mono_thread_set_main (MonoThread *thread)
214 MONO_REQ_GC_UNSAFE_MODE;
216 static gboolean registered = FALSE;
219 MONO_GC_REGISTER_ROOT_SINGLE (main_thread, MONO_ROOT_SOURCE_THREADING, "main thread object");
223 main_thread = thread;
227 mono_thread_get_main (void)
229 MONO_REQ_GC_UNSAFE_MODE;
235 mono_type_initialization_init (void)
237 mono_coop_mutex_init_recursive (&type_initialization_section);
238 type_initialization_hash = g_hash_table_new (NULL, NULL);
239 blocked_thread_hash = g_hash_table_new (NULL, NULL);
240 mono_os_mutex_init_recursive (&ldstr_section);
244 mono_type_initialization_cleanup (void)
247 /* This is causing race conditions with
248 * mono_release_type_locks
250 mono_coop_mutex_destroy (&type_initialization_section);
251 g_hash_table_destroy (type_initialization_hash);
252 type_initialization_hash = NULL;
254 mono_os_mutex_destroy (&ldstr_section);
255 g_hash_table_destroy (blocked_thread_hash);
256 blocked_thread_hash = NULL;
262 * get_type_init_exception_for_vtable:
264 * Return the stored type initialization exception for VTABLE.
266 static MonoException*
267 get_type_init_exception_for_vtable (MonoVTable *vtable)
269 MONO_REQ_GC_UNSAFE_MODE;
272 MonoDomain *domain = vtable->domain;
273 MonoClass *klass = vtable->klass;
277 if (!vtable->init_failed)
278 g_error ("Trying to get the init exception for a non-failed vtable of class %s", mono_type_get_full_name (klass));
281 * If the initializing thread was rudely aborted, the exception is not stored
285 mono_domain_lock (domain);
286 if (domain->type_init_exception_hash)
287 ex = (MonoException *)mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
288 mono_domain_unlock (domain);
291 if (klass->name_space && *klass->name_space)
292 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
294 full_name = g_strdup (klass->name);
295 ex = mono_get_exception_type_initialization_checked (full_name, NULL, &error);
297 return_val_if_nok (&error, NULL);
304 * mono_runtime_class_init:
305 * @vtable: vtable that needs to be initialized
307 * This routine calls the class constructor for @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 * @vtable that neeeds to be initialized
340 * @error set on error
342 * returns TRUE if class constructor .cctor has been initialized successfully, or FALSE otherwise and sets @error.
346 mono_runtime_class_init_full (MonoVTable *vtable, MonoError *error)
348 MONO_REQ_GC_UNSAFE_MODE;
350 MonoMethod *method = NULL;
353 MonoDomain *domain = vtable->domain;
354 TypeInitializationLock *lock;
355 MonoNativeThreadId tid;
356 int do_initialization = 0;
357 MonoDomain *last_domain = NULL;
358 MonoException * pending_tae = NULL;
362 if (vtable->initialized)
365 klass = vtable->klass;
367 if (!klass->image->checked_module_cctor) {
368 mono_image_check_for_module_cctor (klass->image);
369 if (klass->image->has_module_cctor) {
370 MonoClass *module_klass;
371 MonoVTable *module_vtable;
373 module_klass = mono_class_get_checked (klass->image, MONO_TOKEN_TYPE_DEF | 1, error);
378 module_vtable = mono_class_vtable_full (vtable->domain, module_klass, error);
381 if (!mono_runtime_class_init_full (module_vtable, error))
385 method = mono_class_get_cctor (klass);
387 vtable->initialized = 1;
391 tid = mono_native_thread_id_get ();
394 * Due some preprocessing inside a global lock. If we are the first thread
395 * trying to initialize this class, create a separate lock+cond var, and
396 * acquire it before leaving the global lock. The other threads will wait
400 mono_type_initialization_lock ();
401 /* double check... */
402 if (vtable->initialized) {
403 mono_type_initialization_unlock ();
406 if (vtable->init_failed) {
407 mono_type_initialization_unlock ();
409 /* The type initialization already failed once, rethrow the same exception */
410 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
413 lock = (TypeInitializationLock *)g_hash_table_lookup (type_initialization_hash, vtable);
415 /* This thread will get to do the initialization */
416 if (mono_domain_get () != domain) {
417 /* Transfer into the target domain */
418 last_domain = mono_domain_get ();
419 if (!mono_domain_set (domain, FALSE)) {
420 vtable->initialized = 1;
421 mono_type_initialization_unlock ();
422 mono_error_set_exception_instance (error, mono_get_exception_appdomain_unloaded ());
426 lock = (TypeInitializationLock *)g_malloc0 (sizeof (TypeInitializationLock));
427 mono_coop_mutex_init_recursive (&lock->mutex);
428 mono_coop_cond_init (&lock->cond);
429 lock->initializing_tid = tid;
430 lock->waiting_count = 1;
432 g_hash_table_insert (type_initialization_hash, vtable, lock);
433 do_initialization = 1;
436 TypeInitializationLock *pending_lock;
438 if (mono_native_thread_id_equals (lock->initializing_tid, tid)) {
439 mono_type_initialization_unlock ();
442 /* see if the thread doing the initialization is already blocked on this thread */
443 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (lock->initializing_tid));
444 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
445 if (mono_native_thread_id_equals (pending_lock->initializing_tid, tid)) {
446 if (!pending_lock->done) {
447 mono_type_initialization_unlock ();
450 /* the thread doing the initialization is blocked on this thread,
451 but on a lock that has already been freed. It just hasn't got
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 */
460 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
462 mono_type_initialization_unlock ();
464 if (do_initialization) {
465 MonoException *exc = NULL;
467 /* We are holding the per-vtable lock, do the actual initialization */
469 mono_threads_begin_abort_protected_block ();
470 mono_runtime_try_invoke (method, NULL, NULL, (MonoObject**) &exc, error);
471 gboolean got_pending_interrupt = mono_threads_end_abort_protected_block ();
473 //exception extracted, error will be set to the right value later
474 if (exc == NULL && !mono_error_ok (error))//invoking failed but exc was not set
475 exc = mono_error_convert_to_exception (error);
477 mono_error_cleanup (error);
481 /* If the initialization failed, mark the class as unusable. */
482 /* Avoid infinite loops */
484 (klass->image == mono_defaults.corlib &&
485 !strcmp (klass->name_space, "System") &&
486 !strcmp (klass->name, "TypeInitializationException")))) {
487 vtable->init_failed = 1;
489 if (klass->name_space && *klass->name_space)
490 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
492 full_name = g_strdup (klass->name);
494 MonoException *exc_to_throw = mono_get_exception_type_initialization_checked (full_name, exc, error);
497 mono_error_assert_ok (error); //We can't recover from this, no way to fail a type we can't alloc a failure.
500 * Store the exception object so it could be thrown on subsequent
503 mono_domain_lock (domain);
504 if (!domain->type_init_exception_hash)
505 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");
506 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
507 mono_domain_unlock (domain);
511 mono_domain_set (last_domain, TRUE);
513 /* Signal to the other threads that we are done */
514 mono_type_init_lock (lock);
516 mono_coop_cond_broadcast (&lock->cond);
517 mono_type_init_unlock (lock);
519 //This can happen if the cctor self-aborts
520 if (exc && mono_object_class (exc) == mono_defaults.threadabortexception_class)
523 //TAEs are blocked around .cctors, they must escape as soon as no cctor is left to run.
524 if (!pending_tae && got_pending_interrupt)
525 pending_tae = mono_thread_try_resume_interruption ();
527 /* this just blocks until the initializing thread is done */
528 mono_type_init_lock (lock);
530 mono_coop_cond_wait (&lock->cond, &lock->mutex);
531 mono_type_init_unlock (lock);
534 /* Do cleanup and setting vtable->initialized inside the global lock again */
535 mono_type_initialization_lock ();
536 if (!do_initialization)
537 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
538 gboolean deleted = unref_type_lock (lock);
540 g_hash_table_remove (type_initialization_hash, vtable);
541 /* Have to set this here since we check it inside the global lock */
542 if (do_initialization && !vtable->init_failed)
543 vtable->initialized = 1;
544 mono_type_initialization_unlock ();
548 mono_error_set_exception_instance (error, pending_tae);
549 else if (vtable->init_failed) {
550 /* Either we were the initializing thread or we waited for the initialization */
551 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
558 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
560 MONO_REQ_GC_NEUTRAL_MODE;
562 MonoVTable *vtable = (MonoVTable*)key;
564 TypeInitializationLock *lock = (TypeInitializationLock*) value;
565 if (mono_native_thread_id_equals (lock->initializing_tid, MONO_UINT_TO_NATIVE_THREAD_ID (GPOINTER_TO_UINT (user))) && !lock->done) {
568 * Have to set this since it cannot be set by the normal code in
569 * mono_runtime_class_init (). In this case, the exception object is not stored,
570 * and get_type_init_exception_for_class () needs to be aware of this.
572 mono_type_init_lock (lock);
573 vtable->init_failed = 1;
574 mono_coop_cond_broadcast (&lock->cond);
575 mono_type_init_unlock (lock);
576 gboolean deleted = unref_type_lock (lock);
584 mono_release_type_locks (MonoInternalThread *thread)
586 MONO_REQ_GC_UNSAFE_MODE;
588 mono_type_initialization_lock ();
589 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, GUINT_TO_POINTER (thread->tid));
590 mono_type_initialization_unlock ();
593 #ifndef DISABLE_REMOTING
596 create_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error)
598 if (!callbacks.create_remoting_trampoline)
599 g_error ("remoting not installed");
600 return callbacks.create_remoting_trampoline (domain, method, target, error);
605 static MonoImtTrampolineBuilder imt_trampoline_builder;
606 static gboolean always_build_imt_trampolines;
608 #if (MONO_IMT_SIZE > 32)
609 #error "MONO_IMT_SIZE cannot be larger than 32"
613 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
615 memcpy (&callbacks, cbs, sizeof (*cbs));
618 MonoRuntimeCallbacks*
619 mono_get_runtime_callbacks (void)
625 mono_install_imt_trampoline_builder (MonoImtTrampolineBuilder func)
627 imt_trampoline_builder = func;
631 mono_set_always_build_imt_trampolines (gboolean value)
633 always_build_imt_trampolines = value;
637 * mono_compile_method:
638 * @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:
654 * @method: The method to compile.
655 * @error: set on error.
657 * This JIT-compiles the method, and returns the pointer to the native code
658 * produced. On failure returns NULL and sets @error.
661 mono_compile_method_checked (MonoMethod *method, MonoError *error)
665 MONO_REQ_GC_NEUTRAL_MODE
669 g_assert (callbacks.compile_method);
670 res = callbacks.compile_method (method, error);
675 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper, MonoError *error)
679 MONO_REQ_GC_NEUTRAL_MODE;
682 res = callbacks.create_jump_trampoline (domain, method, add_sync_wrapper, error);
687 mono_runtime_create_delegate_trampoline (MonoClass *klass)
689 MONO_REQ_GC_NEUTRAL_MODE
691 g_assert (callbacks.create_delegate_trampoline);
692 return callbacks.create_delegate_trampoline (mono_domain_get (), klass);
696 * mono_runtime_free_method:
697 * @domain; domain where the method is hosted
698 * @method: method to release
700 * This routine is invoked to free the resources associated with
701 * a method that has been JIT compiled. This is used to discard
702 * methods that were used only temporarily (for example, used in marshalling)
706 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
708 MONO_REQ_GC_NEUTRAL_MODE
710 if (callbacks.free_method)
711 callbacks.free_method (domain, method);
713 mono_method_clear_object (domain, method);
715 mono_free_method (method);
719 * The vtables in the root appdomain are assumed to be reachable by other
720 * roots, and we don't use typed allocation in the other domains.
723 /* The sync block is no longer a GC pointer */
724 #define GC_HEADER_BITMAP (0)
726 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
729 compute_class_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
731 MONO_REQ_GC_NEUTRAL_MODE;
733 MonoClassField *field;
739 max_size = mono_class_data_size (klass) / sizeof (gpointer);
741 max_size = klass->instance_size / sizeof (gpointer);
742 if (max_size > size) {
743 g_assert (offset <= 0);
744 bitmap = (gsize *)g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
749 /*An Ephemeron cannot be marked by sgen*/
750 if (!static_fields && klass->image == mono_defaults.corlib && !strcmp ("Ephemeron", klass->name)) {
752 memset (bitmap, 0, size / 8);
757 for (p = klass; p != NULL; p = p->parent) {
758 gpointer iter = NULL;
759 while ((field = mono_class_get_fields (p, &iter))) {
763 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
765 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
768 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
771 /* FIXME: should not happen, flag as type load error */
772 if (field->type->byref)
775 if (static_fields && field->offset == -1)
779 pos = field->offset / sizeof (gpointer);
782 type = mono_type_get_underlying_type (field->type);
783 switch (type->type) {
787 case MONO_TYPE_FNPTR:
789 case MONO_TYPE_STRING:
790 case MONO_TYPE_SZARRAY:
791 case MONO_TYPE_CLASS:
792 case MONO_TYPE_OBJECT:
793 case MONO_TYPE_ARRAY:
794 g_assert ((field->offset % sizeof(gpointer)) == 0);
796 g_assert (pos < size || pos <= max_size);
797 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
798 *max_set = MAX (*max_set, pos);
800 case MONO_TYPE_GENERICINST:
801 if (!mono_type_generic_inst_is_valuetype (type)) {
802 g_assert ((field->offset % sizeof(gpointer)) == 0);
804 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
805 *max_set = MAX (*max_set, pos);
810 case MONO_TYPE_VALUETYPE: {
811 MonoClass *fclass = mono_class_from_mono_type (field->type);
812 if (fclass->has_references) {
813 /* remove the object header */
814 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
828 case MONO_TYPE_BOOLEAN:
832 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
843 * mono_class_compute_bitmap:
845 * Mono internal function to compute a bitmap of reference fields in a class.
848 mono_class_compute_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
850 MONO_REQ_GC_NEUTRAL_MODE;
852 return compute_class_bitmap (klass, bitmap, size, offset, max_set, static_fields);
857 * similar to the above, but sets the bits in the bitmap for any non-ref field
858 * and ignores static fields
861 compute_class_non_ref_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset)
863 MonoClassField *field;
868 max_size = class->instance_size / sizeof (gpointer);
869 if (max_size >= size) {
870 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
873 for (p = class; p != NULL; p = p->parent) {
874 gpointer iter = NULL;
875 while ((field = mono_class_get_fields (p, &iter))) {
878 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
880 /* FIXME: should not happen, flag as type load error */
881 if (field->type->byref)
884 pos = field->offset / sizeof (gpointer);
887 type = mono_type_get_underlying_type (field->type);
888 switch (type->type) {
889 #if SIZEOF_VOID_P == 8
893 case MONO_TYPE_FNPTR:
898 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
899 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
900 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
903 #if SIZEOF_VOID_P == 4
907 case MONO_TYPE_FNPTR:
912 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
913 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
914 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
920 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
921 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
922 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
925 case MONO_TYPE_BOOLEAN:
928 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
930 case MONO_TYPE_STRING:
931 case MONO_TYPE_SZARRAY:
932 case MONO_TYPE_CLASS:
933 case MONO_TYPE_OBJECT:
934 case MONO_TYPE_ARRAY:
936 case MONO_TYPE_GENERICINST:
937 if (!mono_type_generic_inst_is_valuetype (type)) {
942 case MONO_TYPE_VALUETYPE: {
943 MonoClass *fclass = mono_class_from_mono_type (field->type);
944 /* remove the object header */
945 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
949 g_assert_not_reached ();
958 * mono_class_insecure_overlapping:
959 * check if a class with explicit layout has references and non-references
960 * fields overlapping.
962 * Returns: TRUE if it is insecure to load the type.
965 mono_class_insecure_overlapping (MonoClass *klass)
969 gsize default_bitmap [4] = {0};
971 gsize default_nrbitmap [4] = {0};
972 int i, insecure = FALSE;
975 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
976 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
978 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
979 int idx = i % (sizeof (bitmap [0]) * 8);
980 if (bitmap [idx] & nrbitmap [idx]) {
985 if (bitmap != default_bitmap)
987 if (nrbitmap != default_nrbitmap)
990 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
998 ves_icall_string_alloc (int length)
1001 MonoString *str = mono_string_new_size_checked (mono_domain_get (), length, &error);
1002 mono_error_set_pending_exception (&error);
1007 /* LOCKING: Acquires the loader lock */
1009 mono_class_compute_gc_descriptor (MonoClass *klass)
1011 MONO_REQ_GC_NEUTRAL_MODE;
1015 gsize default_bitmap [4] = {0};
1016 static gboolean gcj_inited = FALSE;
1017 MonoGCDescriptor gc_descr;
1020 mono_loader_lock ();
1022 mono_register_jit_icall (ves_icall_object_new_fast, "ves_icall_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
1023 mono_register_jit_icall (ves_icall_string_alloc, "ves_icall_string_alloc", mono_create_icall_signature ("object int"), FALSE);
1026 mono_loader_unlock ();
1030 mono_class_init (klass);
1032 if (klass->gc_descr_inited)
1035 bitmap = default_bitmap;
1036 if (klass == mono_defaults.string_class) {
1037 gc_descr = mono_gc_make_descr_for_string (bitmap, 2);
1038 } else if (klass->rank) {
1039 mono_class_compute_gc_descriptor (klass->element_class);
1040 if (MONO_TYPE_IS_REFERENCE (&klass->element_class->byval_arg)) {
1042 gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
1043 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1044 class->name_space, class->name);*/
1046 /* remove the object header */
1047 bitmap = compute_class_bitmap (klass->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
1048 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));
1049 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1050 class->name_space, class->name);*/
1051 if (bitmap != default_bitmap)
1055 /*static int count = 0;
1058 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1059 gc_descr = mono_gc_make_descr_for_object (bitmap, max_set + 1, klass->instance_size);
1061 if (class->gc_descr == MONO_GC_DESCRIPTOR_NULL)
1062 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
1064 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
1065 if (bitmap != default_bitmap)
1069 /* Publish the data */
1070 mono_loader_lock ();
1071 klass->gc_descr = gc_descr;
1072 mono_memory_barrier ();
1073 klass->gc_descr_inited = TRUE;
1074 mono_loader_unlock ();
1078 * field_is_special_static:
1079 * @fklass: The MonoClass to look up.
1080 * @field: The MonoClassField describing the field.
1082 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1083 * SPECIAL_STATIC_NONE otherwise.
1086 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1088 MONO_REQ_GC_NEUTRAL_MODE;
1091 MonoCustomAttrInfo *ainfo;
1093 ainfo = mono_custom_attrs_from_field_checked (fklass, field, &error);
1094 mono_error_cleanup (&error); /* FIXME don't swallow the error? */
1097 for (i = 0; i < ainfo->num_attrs; ++i) {
1098 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1099 if (klass->image == mono_defaults.corlib) {
1100 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1101 mono_custom_attrs_free (ainfo);
1102 return SPECIAL_STATIC_THREAD;
1104 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1105 mono_custom_attrs_free (ainfo);
1106 return SPECIAL_STATIC_CONTEXT;
1110 mono_custom_attrs_free (ainfo);
1111 return SPECIAL_STATIC_NONE;
1114 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1115 #define mix(a,b,c) { \
1116 a -= c; a ^= rot(c, 4); c += b; \
1117 b -= a; b ^= rot(a, 6); a += c; \
1118 c -= b; c ^= rot(b, 8); b += a; \
1119 a -= c; a ^= rot(c,16); c += b; \
1120 b -= a; b ^= rot(a,19); a += c; \
1121 c -= b; c ^= rot(b, 4); b += a; \
1123 #define final(a,b,c) { \
1124 c ^= b; c -= rot(b,14); \
1125 a ^= c; a -= rot(c,11); \
1126 b ^= a; b -= rot(a,25); \
1127 c ^= b; c -= rot(b,16); \
1128 a ^= c; a -= rot(c,4); \
1129 b ^= a; b -= rot(a,14); \
1130 c ^= b; c -= rot(b,24); \
1134 * mono_method_get_imt_slot:
1136 * The IMT slot is embedded into AOTed code, so this must return the same value
1137 * for the same method across all executions. This means:
1138 * - pointers shouldn't be used as hash values.
1139 * - mono_metadata_str_hash () should be used for hashing strings.
1142 mono_method_get_imt_slot (MonoMethod *method)
1144 MONO_REQ_GC_NEUTRAL_MODE;
1146 MonoMethodSignature *sig;
1148 guint32 *hashes_start, *hashes;
1152 /* This can be used to stress tests the collision code */
1156 * We do this to simplify generic sharing. It will hurt
1157 * performance in cases where a class implements two different
1158 * instantiations of the same generic interface.
1159 * The code in build_imt_slots () depends on this.
1161 if (method->is_inflated)
1162 method = ((MonoMethodInflated*)method)->declaring;
1164 sig = mono_method_signature (method);
1165 hashes_count = sig->param_count + 4;
1166 hashes_start = (guint32 *)malloc (hashes_count * sizeof (guint32));
1167 hashes = hashes_start;
1169 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1170 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1171 method->klass->name_space, method->klass->name, method->name);
1174 /* Initialize hashes */
1175 hashes [0] = mono_metadata_str_hash (method->klass->name);
1176 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1177 hashes [2] = mono_metadata_str_hash (method->name);
1178 hashes [3] = mono_metadata_type_hash (sig->ret);
1179 for (i = 0; i < sig->param_count; i++) {
1180 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1183 /* Setup internal state */
1184 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1186 /* Handle most of the hashes */
1187 while (hashes_count > 3) {
1196 /* Handle the last 3 hashes (all the case statements fall through) */
1197 switch (hashes_count) {
1198 case 3 : c += hashes [2];
1199 case 2 : b += hashes [1];
1200 case 1 : a += hashes [0];
1202 case 0: /* nothing left to add */
1206 g_free (hashes_start);
1207 /* Report the result */
1208 return c % MONO_IMT_SIZE;
1217 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1218 MONO_REQ_GC_NEUTRAL_MODE;
1220 guint32 imt_slot = mono_method_get_imt_slot (method);
1221 MonoImtBuilderEntry *entry;
1223 if (slot_num >= 0 && imt_slot != slot_num) {
1224 /* we build just a single imt slot and this is not it */
1228 entry = (MonoImtBuilderEntry *)g_malloc0 (sizeof (MonoImtBuilderEntry));
1229 entry->key = method;
1230 entry->value.vtable_slot = vtable_slot;
1231 entry->next = imt_builder [imt_slot];
1232 if (imt_builder [imt_slot] != NULL) {
1233 entry->children = imt_builder [imt_slot]->children + 1;
1234 if (entry->children == 1) {
1235 mono_stats.imt_slots_with_collisions++;
1236 *imt_collisions_bitmap |= (1 << imt_slot);
1239 entry->children = 0;
1240 mono_stats.imt_used_slots++;
1242 imt_builder [imt_slot] = entry;
1245 char *method_name = mono_method_full_name (method, TRUE);
1246 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1247 method, method_name, imt_slot, vtable_slot, entry->children);
1248 g_free (method_name);
1255 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1257 MonoMethod *method = e->key;
1258 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1262 method->klass->name_space,
1263 method->klass->name,
1266 printf (" * %s: NULL\n", message);
1272 compare_imt_builder_entries (const void *p1, const void *p2) {
1273 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1274 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1276 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1280 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1282 MONO_REQ_GC_NEUTRAL_MODE;
1284 int count = end - start;
1285 int chunk_start = out_array->len;
1288 for (i = start; i < end; ++i) {
1289 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1290 item->key = sorted_array [i]->key;
1291 item->value = sorted_array [i]->value;
1292 item->has_target_code = sorted_array [i]->has_target_code;
1293 item->is_equals = TRUE;
1295 item->check_target_idx = out_array->len + 1;
1297 item->check_target_idx = 0;
1298 g_ptr_array_add (out_array, item);
1301 int middle = start + count / 2;
1302 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1304 item->key = sorted_array [middle]->key;
1305 item->is_equals = FALSE;
1306 g_ptr_array_add (out_array, item);
1307 imt_emit_ir (sorted_array, start, middle, out_array);
1308 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1314 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1315 MONO_REQ_GC_NEUTRAL_MODE;
1317 int number_of_entries = entries->children + 1;
1318 MonoImtBuilderEntry **sorted_array = (MonoImtBuilderEntry **)malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1319 GPtrArray *result = g_ptr_array_new ();
1320 MonoImtBuilderEntry *current_entry;
1323 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1324 sorted_array [i] = current_entry;
1326 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1328 /*for (i = 0; i < number_of_entries; i++) {
1329 print_imt_entry (" sorted array:", sorted_array [i], i);
1332 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1334 g_free (sorted_array);
1339 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1341 MONO_REQ_GC_NEUTRAL_MODE;
1343 if (imt_builder_entry != NULL) {
1344 if (imt_builder_entry->children == 0 && !fail_tramp && !always_build_imt_trampolines) {
1345 /* No collision, return the vtable slot contents */
1346 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1348 /* Collision, build the trampoline */
1349 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1352 result = imt_trampoline_builder (vtable, domain,
1353 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1354 for (i = 0; i < imt_ir->len; ++i)
1355 g_free (g_ptr_array_index (imt_ir, i));
1356 g_ptr_array_free (imt_ir, TRUE);
1368 static MonoImtBuilderEntry*
1369 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1372 * LOCKING: requires the loader and domain locks.
1376 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1378 MONO_REQ_GC_NEUTRAL_MODE;
1382 guint32 imt_collisions_bitmap = 0;
1383 MonoImtBuilderEntry **imt_builder = (MonoImtBuilderEntry **)calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1384 int method_count = 0;
1385 gboolean record_method_count_for_max_collisions = FALSE;
1386 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1389 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1391 for (i = 0; i < klass->interface_offsets_count; ++i) {
1392 MonoClass *iface = klass->interfaces_packed [i];
1393 int interface_offset = klass->interface_offsets_packed [i];
1394 int method_slot_in_interface, vt_slot;
1396 if (mono_class_has_variant_generic_params (iface))
1397 has_variant_iface = TRUE;
1399 mono_class_setup_methods (iface);
1400 vt_slot = interface_offset;
1401 int mcount = mono_class_get_method_count (iface);
1402 for (method_slot_in_interface = 0; method_slot_in_interface < mcount; method_slot_in_interface++) {
1405 if (slot_num >= 0 && mono_class_is_ginst (iface)) {
1407 * The imt slot of the method is the same as for its declaring method,
1408 * see the comment in mono_method_get_imt_slot (), so we can
1409 * avoid inflating methods which will be discarded by
1410 * add_imt_builder_entry anyway.
1412 method = mono_class_get_method_by_index (mono_class_get_generic_class (iface)->container_class, method_slot_in_interface);
1413 if (mono_method_get_imt_slot (method) != slot_num) {
1418 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1419 if (method->is_generic) {
1420 has_generic_virtual = TRUE;
1425 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1426 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1431 if (extra_interfaces) {
1432 int interface_offset = klass->vtable_size;
1434 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1435 MonoClass* iface = (MonoClass *)list_item->data;
1436 int method_slot_in_interface;
1437 int mcount = mono_class_get_method_count (iface);
1438 for (method_slot_in_interface = 0; method_slot_in_interface < mcount; method_slot_in_interface++) {
1439 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1441 if (method->is_generic)
1442 has_generic_virtual = TRUE;
1443 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1445 interface_offset += mcount;
1448 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1449 /* overwrite the imt slot only if we're building all the entries or if
1450 * we're building this specific one
1452 if (slot_num < 0 || i == slot_num) {
1453 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1456 if (imt_builder [i]) {
1457 MonoImtBuilderEntry *entry;
1459 /* Link entries with imt_builder [i] */
1460 for (entry = entries; entry->next; entry = entry->next) {
1462 MonoMethod *method = (MonoMethod*)entry->key;
1463 char *method_name = mono_method_full_name (method, TRUE);
1464 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1465 g_free (method_name);
1468 entry->next = imt_builder [i];
1469 entries->children += imt_builder [i]->children + 1;
1471 imt_builder [i] = entries;
1474 if (has_generic_virtual || has_variant_iface) {
1476 * There might be collisions later when the the trampoline is expanded.
1478 imt_collisions_bitmap |= (1 << i);
1481 * The IMT trampoline might be called with an instance of one of the
1482 * generic virtual methods, so has to fallback to the IMT trampoline.
1484 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline (vt, i));
1486 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1489 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1493 if (imt_builder [i] != NULL) {
1494 int methods_in_slot = imt_builder [i]->children + 1;
1495 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1496 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1497 record_method_count_for_max_collisions = TRUE;
1499 method_count += methods_in_slot;
1503 mono_stats.imt_number_of_methods += method_count;
1504 if (record_method_count_for_max_collisions) {
1505 mono_stats.imt_method_count_when_max_collisions = method_count;
1508 for (i = 0; i < MONO_IMT_SIZE; i++) {
1509 MonoImtBuilderEntry* entry = imt_builder [i];
1510 while (entry != NULL) {
1511 MonoImtBuilderEntry* next = entry->next;
1516 g_free (imt_builder);
1517 /* we OR the bitmap since we may build just a single imt slot at a time */
1518 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1522 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1523 MONO_REQ_GC_NEUTRAL_MODE;
1525 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1529 * mono_vtable_build_imt_slot:
1530 * @vtable: virtual object table struct
1531 * @imt_slot: slot in the IMT table
1533 * Fill the given @imt_slot in the IMT table of @vtable with
1534 * a trampoline or a trampoline for the case of collisions.
1535 * This is part of the internal mono API.
1537 * LOCKING: Take the domain lock.
1540 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1542 MONO_REQ_GC_NEUTRAL_MODE;
1544 gpointer *imt = (gpointer*)vtable;
1545 imt -= MONO_IMT_SIZE;
1546 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1548 /* no support for extra interfaces: the proxy objects will need
1549 * to build the complete IMT
1550 * Update and heck needs to ahppen inside the proper domain lock, as all
1551 * the changes made to a MonoVTable.
1553 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1554 mono_domain_lock (vtable->domain);
1555 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1556 if (!callbacks.imt_entry_inited (vtable, imt_slot))
1557 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1558 mono_domain_unlock (vtable->domain);
1559 mono_loader_unlock ();
1562 #define THUNK_THRESHOLD 10
1565 * mono_method_alloc_generic_virtual_trampoline:
1567 * @size: size in bytes
1569 * Allocs size bytes to be used for the code of a generic virtual
1570 * trampoline. It's either allocated from the domain's code manager or
1571 * reused from a previously invalidated piece.
1573 * LOCKING: The domain lock must be held.
1576 mono_method_alloc_generic_virtual_trampoline (MonoDomain *domain, int size)
1578 MONO_REQ_GC_NEUTRAL_MODE;
1580 static gboolean inited = FALSE;
1581 static int generic_virtual_trampolines_size = 0;
1584 mono_counters_register ("Generic virtual trampoline bytes",
1585 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_trampolines_size);
1588 generic_virtual_trampolines_size += size;
1590 return mono_domain_code_reserve (domain, size);
1593 typedef struct _GenericVirtualCase {
1597 struct _GenericVirtualCase *next;
1598 } GenericVirtualCase;
1601 * get_generic_virtual_entries:
1603 * Return IMT entries for the generic virtual method instances and
1604 * variant interface methods for vtable slot
1607 static MonoImtBuilderEntry*
1608 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1610 MONO_REQ_GC_NEUTRAL_MODE;
1612 GenericVirtualCase *list;
1613 MonoImtBuilderEntry *entries;
1615 mono_domain_lock (domain);
1616 if (!domain->generic_virtual_cases)
1617 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1619 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1622 for (; list; list = list->next) {
1623 MonoImtBuilderEntry *entry;
1625 if (list->count < THUNK_THRESHOLD)
1628 entry = g_new0 (MonoImtBuilderEntry, 1);
1629 entry->key = list->method;
1630 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1631 entry->has_target_code = 1;
1633 entry->children = entries->children + 1;
1634 entry->next = entries;
1638 mono_domain_unlock (domain);
1640 /* FIXME: Leaking memory ? */
1645 * mono_method_add_generic_virtual_invocation:
1647 * @vtable_slot: pointer to the vtable slot
1648 * @method: the inflated generic virtual method
1649 * @code: the method's code
1651 * Registers a call via unmanaged code to a generic virtual method
1652 * instantiation or variant interface method. If the number of calls reaches a threshold
1653 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1654 * virtual method trampoline.
1657 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1658 gpointer *vtable_slot,
1659 MonoMethod *method, gpointer code)
1661 MONO_REQ_GC_NEUTRAL_MODE;
1663 static gboolean inited = FALSE;
1664 static int num_added = 0;
1665 static int num_freed = 0;
1667 GenericVirtualCase *gvc, *list;
1668 MonoImtBuilderEntry *entries;
1672 mono_domain_lock (domain);
1673 if (!domain->generic_virtual_cases)
1674 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1677 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1678 mono_counters_register ("Freed IMT trampolines", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_freed);
1682 /* Check whether the case was already added */
1683 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1686 if (gvc->method == method)
1691 /* If not found, make a new one */
1693 gvc = (GenericVirtualCase *)mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1694 gvc->method = method;
1697 gvc->next = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1699 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1704 if (++gvc->count == THUNK_THRESHOLD) {
1705 gpointer *old_thunk = (void **)*vtable_slot;
1706 gpointer vtable_trampoline = NULL;
1707 gpointer imt_trampoline = NULL;
1709 if ((gpointer)vtable_slot < (gpointer)vtable) {
1710 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1711 int imt_slot = MONO_IMT_SIZE + displacement;
1713 /* Force the rebuild of the trampoline at the next call */
1714 imt_trampoline = callbacks.get_imt_trampoline (vtable, imt_slot);
1715 *vtable_slot = imt_trampoline;
1717 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline (vtable, (gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1719 entries = get_generic_virtual_entries (domain, vtable_slot);
1721 sorted = imt_sort_slot_entries (entries);
1723 *vtable_slot = imt_trampoline_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1727 MonoImtBuilderEntry *next = entries->next;
1732 for (i = 0; i < sorted->len; ++i)
1733 g_free (g_ptr_array_index (sorted, i));
1734 g_ptr_array_free (sorted, TRUE);
1736 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1741 mono_domain_unlock (domain);
1744 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error);
1747 * mono_class_vtable:
1748 * @domain: the application domain
1749 * @class: the class to initialize
1751 * VTables are domain specific because we create domain specific code, and
1752 * they contain the domain specific static class data.
1753 * On failure, NULL is returned, and class->exception_type is set.
1756 mono_class_vtable (MonoDomain *domain, MonoClass *klass)
1759 MonoVTable* vtable = mono_class_vtable_full (domain, klass, &error);
1760 mono_error_cleanup (&error);
1765 * mono_class_vtable_full:
1766 * @domain: the application domain
1767 * @class: the class to initialize
1768 * @error set on failure.
1770 * VTables are domain specific because we create domain specific code, and
1771 * they contain the domain specific static class data.
1774 mono_class_vtable_full (MonoDomain *domain, MonoClass *klass, MonoError *error)
1776 MONO_REQ_GC_UNSAFE_MODE;
1778 MonoClassRuntimeInfo *runtime_info;
1784 if (mono_class_has_failure (klass)) {
1785 mono_error_set_for_class_failure (error, klass);
1789 /* this check can be inlined in jitted code, too */
1790 runtime_info = klass->runtime_info;
1791 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1792 return runtime_info->domain_vtables [domain->domain_id];
1793 return mono_class_create_runtime_vtable (domain, klass, error);
1797 * mono_class_try_get_vtable:
1798 * @domain: the application domain
1799 * @class: the class to initialize
1801 * This function tries to get the associated vtable from @class if
1802 * it was already created.
1805 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *klass)
1807 MONO_REQ_GC_NEUTRAL_MODE;
1809 MonoClassRuntimeInfo *runtime_info;
1813 runtime_info = klass->runtime_info;
1814 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1815 return runtime_info->domain_vtables [domain->domain_id];
1820 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1822 MONO_REQ_GC_NEUTRAL_MODE;
1824 size_t alloc_offset;
1827 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1828 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1829 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1831 if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1832 g_assert ((imt_table_bytes & 7) == 4);
1839 return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1843 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error)
1845 MONO_REQ_GC_UNSAFE_MODE;
1848 MonoClassRuntimeInfo *runtime_info, *old_info;
1849 MonoClassField *field;
1851 int i, vtable_slots;
1852 size_t imt_table_bytes;
1854 guint32 vtable_size, class_size;
1856 gpointer *interface_offsets;
1860 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1861 mono_domain_lock (domain);
1862 runtime_info = klass->runtime_info;
1863 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1864 mono_domain_unlock (domain);
1865 mono_loader_unlock ();
1866 return runtime_info->domain_vtables [domain->domain_id];
1868 if (!klass->inited || mono_class_has_failure (klass)) {
1869 if (!mono_class_init (klass) || mono_class_has_failure (klass)) {
1870 mono_domain_unlock (domain);
1871 mono_loader_unlock ();
1872 mono_error_set_for_class_failure (error, klass);
1877 /* Array types require that their element type be valid*/
1878 if (klass->byval_arg.type == MONO_TYPE_ARRAY || klass->byval_arg.type == MONO_TYPE_SZARRAY) {
1879 MonoClass *element_class = klass->element_class;
1880 if (!element_class->inited)
1881 mono_class_init (element_class);
1883 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1884 if (!mono_class_has_failure (element_class) && !element_class->vtable_size)
1885 mono_class_setup_vtable (element_class);
1887 if (mono_class_has_failure (element_class)) {
1888 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1889 if (!mono_class_has_failure (klass))
1890 mono_class_set_type_load_failure (klass, "");
1891 mono_domain_unlock (domain);
1892 mono_loader_unlock ();
1893 mono_error_set_for_class_failure (error, klass);
1899 * For some classes, mono_class_init () already computed klass->vtable_size, and
1900 * that is all that is needed because of the vtable trampolines.
1902 if (!klass->vtable_size)
1903 mono_class_setup_vtable (klass);
1905 if (mono_class_is_ginst (klass) && !klass->vtable)
1906 mono_class_check_vtable_constraints (klass, NULL);
1908 /* Initialize klass->has_finalize */
1909 mono_class_has_finalizer (klass);
1911 if (mono_class_has_failure (klass)) {
1912 mono_domain_unlock (domain);
1913 mono_loader_unlock ();
1914 mono_error_set_for_class_failure (error, klass);
1918 vtable_slots = klass->vtable_size;
1919 /* we add an additional vtable slot to store the pointer to static field data only when needed */
1920 class_size = mono_class_data_size (klass);
1924 if (klass->interface_offsets_count) {
1925 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1926 mono_stats.imt_number_of_tables++;
1927 mono_stats.imt_tables_size += imt_table_bytes;
1929 imt_table_bytes = 0;
1932 vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
1934 mono_stats.used_class_count++;
1935 mono_stats.class_vtable_size += vtable_size;
1937 interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
1938 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1939 g_assert (!((gsize)vt & 7));
1942 vt->rank = klass->rank;
1943 vt->domain = domain;
1945 mono_class_compute_gc_descriptor (klass);
1947 * We can't use typed allocation in the non-root domains, since the
1948 * collector needs the GC descriptor stored in the vtable even after
1949 * the mempool containing the vtable is destroyed when the domain is
1950 * unloaded. An alternative might be to allocate vtables in the GC
1951 * heap, but this does not seem to work (it leads to crashes inside
1952 * libgc). If that approach is tried, two gc descriptors need to be
1953 * allocated for each class: one for the root domain, and one for all
1954 * other domains. The second descriptor should contain a bit for the
1955 * vtable field in MonoObject, since we can no longer assume the
1956 * vtable is reachable by other roots after the appdomain is unloaded.
1958 #ifdef HAVE_BOEHM_GC
1959 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1960 vt->gc_descr = MONO_GC_DESCRIPTOR_NULL;
1963 vt->gc_descr = klass->gc_descr;
1965 gc_bits = mono_gc_get_vtable_bits (klass);
1966 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
1968 vt->gc_bits = gc_bits;
1971 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
1972 if (klass->has_static_refs) {
1973 MonoGCDescriptor statics_gc_descr;
1975 gsize default_bitmap [4] = {0};
1978 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1979 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], klass->name_space, klass->name, class_size);*/
1980 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1981 vt->vtable [klass->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr, MONO_ROOT_SOURCE_STATIC, "managed static variables");
1982 mono_domain_add_class_static_data (domain, klass, vt->vtable [klass->vtable_size], NULL);
1983 if (bitmap != default_bitmap)
1986 vt->vtable [klass->vtable_size] = mono_domain_alloc0 (domain, class_size);
1988 vt->has_static_fields = TRUE;
1989 mono_stats.class_static_data_size += class_size;
1993 while ((field = mono_class_get_fields (klass, &iter))) {
1994 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1996 if (mono_field_is_deleted (field))
1998 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1999 gint32 special_static = klass->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (klass, field);
2000 if (special_static != SPECIAL_STATIC_NONE) {
2001 guint32 size, offset;
2003 gsize default_bitmap [4] = {0};
2008 if (mono_type_is_reference (field->type)) {
2009 default_bitmap [0] = 1;
2011 bitmap = default_bitmap;
2012 } else if (mono_type_is_struct (field->type)) {
2013 fclass = mono_class_from_mono_type (field->type);
2014 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
2015 numbits = max_set + 1;
2017 default_bitmap [0] = 0;
2019 bitmap = default_bitmap;
2021 size = mono_type_size (field->type, &align);
2022 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
2023 if (!domain->special_static_fields)
2024 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2025 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2026 if (bitmap != default_bitmap)
2029 * This marks the field as special static to speed up the
2030 * checks in mono_field_static_get/set_value ().
2036 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2037 MonoClass *fklass = mono_class_from_mono_type (field->type);
2038 const char *data = mono_field_get_data (field);
2040 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2041 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2042 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2045 if (fklass->valuetype) {
2046 memcpy (t, data, mono_class_value_size (fklass, NULL));
2048 /* it's a pointer type: add check */
2049 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2056 vt->max_interface_id = klass->max_interface_id;
2057 vt->interface_bitmap = klass->interface_bitmap;
2059 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2060 // class->name, klass->interface_offsets_count);
2062 /* Initialize vtable */
2063 if (callbacks.get_vtable_trampoline) {
2064 // This also covers the AOT case
2065 for (i = 0; i < klass->vtable_size; ++i) {
2066 vt->vtable [i] = callbacks.get_vtable_trampoline (vt, i);
2069 mono_class_setup_vtable (klass);
2071 for (i = 0; i < klass->vtable_size; ++i) {
2074 cm = klass->vtable [i];
2076 vt->vtable [i] = callbacks.create_jit_trampoline (domain, cm, error);
2077 if (!is_ok (error)) {
2078 mono_domain_unlock (domain);
2079 mono_loader_unlock ();
2086 if (imt_table_bytes) {
2087 /* Now that the vtable is full, we can actually fill up the IMT */
2088 for (i = 0; i < MONO_IMT_SIZE; ++i)
2089 interface_offsets [i] = callbacks.get_imt_trampoline (vt, i);
2093 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2094 * re-acquire them and check if another thread has created the vtable in the meantime.
2096 /* Special case System.MonoType to avoid infinite recursion */
2097 if (klass != mono_defaults.runtimetype_class) {
2098 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2099 if (!is_ok (error)) {
2100 mono_domain_unlock (domain);
2101 mono_loader_unlock ();
2105 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2106 /* This is unregistered in
2107 unregister_vtable_reflection_type() in
2109 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2112 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (klass));
2114 /* class_vtable_array keeps an array of created vtables
2116 g_ptr_array_add (domain->class_vtable_array, vt);
2117 /* klass->runtime_info is protected by the loader lock, both when
2118 * it it enlarged and when it is stored info.
2122 * Store the vtable in klass->runtime_info.
2123 * klass->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2125 mono_memory_barrier ();
2127 old_info = klass->runtime_info;
2128 if (old_info && old_info->max_domain >= domain->domain_id) {
2129 /* someone already created a large enough runtime info */
2130 old_info->domain_vtables [domain->domain_id] = vt;
2132 int new_size = domain->domain_id;
2134 new_size = MAX (new_size, old_info->max_domain);
2136 /* make the new size a power of two */
2138 while (new_size > i)
2141 /* this is a bounded memory retention issue: may want to
2142 * handle it differently when we'll have a rcu-like system.
2144 runtime_info = (MonoClassRuntimeInfo *)mono_image_alloc0 (klass->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2145 runtime_info->max_domain = new_size - 1;
2146 /* copy the stuff from the older info */
2148 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2150 runtime_info->domain_vtables [domain->domain_id] = vt;
2152 mono_memory_barrier ();
2153 klass->runtime_info = runtime_info;
2156 if (klass == mono_defaults.runtimetype_class) {
2157 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2158 if (!is_ok (error)) {
2159 mono_domain_unlock (domain);
2160 mono_loader_unlock ();
2164 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2165 /* This is unregistered in
2166 unregister_vtable_reflection_type() in
2168 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2171 mono_domain_unlock (domain);
2172 mono_loader_unlock ();
2174 /* make sure the parent is initialized */
2175 /*FIXME shouldn't this fail the current type?*/
2177 mono_class_vtable_full (domain, klass->parent, error);
2182 #ifndef DISABLE_REMOTING
2184 * mono_class_proxy_vtable:
2185 * @domain: the application domain
2186 * @remove_class: the remote class
2187 * @error: set on error
2189 * Creates a vtable for transparent proxies. It is basically
2190 * a copy of the real vtable of the class wrapped in @remote_class,
2191 * but all function pointers invoke the remoting functions, and
2192 * vtable->klass points to the transparent proxy class, and not to @class.
2194 * On failure returns NULL and sets @error
2197 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type, MonoError *error)
2199 MONO_REQ_GC_UNSAFE_MODE;
2201 MonoVTable *vt, *pvt;
2202 int i, j, vtsize, extra_interface_vtsize = 0;
2203 guint32 max_interface_id;
2205 GSList *extra_interfaces = NULL;
2206 MonoClass *klass = remote_class->proxy_class;
2207 gpointer *interface_offsets;
2208 uint8_t *bitmap = NULL;
2210 size_t imt_table_bytes;
2212 #ifdef COMPRESSED_INTERFACE_BITMAP
2218 vt = mono_class_vtable (domain, klass);
2219 g_assert (vt); /*FIXME property handle failure*/
2220 max_interface_id = vt->max_interface_id;
2222 /* Calculate vtable space for extra interfaces */
2223 for (j = 0; j < remote_class->interface_count; j++) {
2224 MonoClass* iclass = remote_class->interfaces[j];
2228 /*FIXME test for interfaces with variant generic arguments*/
2229 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, iclass->interface_id))
2230 continue; /* interface implemented by the class */
2231 if (g_slist_find (extra_interfaces, iclass))
2234 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2236 method_count = mono_class_num_methods (iclass);
2238 ifaces = mono_class_get_implemented_interfaces (iclass, error);
2242 for (i = 0; i < ifaces->len; ++i) {
2243 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2244 /*FIXME test for interfaces with variant generic arguments*/
2245 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, ic->interface_id))
2246 continue; /* interface implemented by the class */
2247 if (g_slist_find (extra_interfaces, ic))
2249 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2250 method_count += mono_class_num_methods (ic);
2252 g_ptr_array_free (ifaces, TRUE);
2256 extra_interface_vtsize += method_count * sizeof (gpointer);
2257 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2260 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2261 mono_stats.imt_number_of_tables++;
2262 mono_stats.imt_tables_size += imt_table_bytes;
2264 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer);
2266 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2268 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2269 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2270 g_assert (!((gsize)pvt & 7));
2272 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer));
2274 pvt->klass = mono_defaults.transparent_proxy_class;
2275 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2276 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2278 /* initialize vtable */
2279 mono_class_setup_vtable (klass);
2280 for (i = 0; i < klass->vtable_size; ++i) {
2283 if ((cm = klass->vtable [i])) {
2284 pvt->vtable [i] = create_remoting_trampoline (domain, cm, target_type, error);
2288 pvt->vtable [i] = NULL;
2291 if (mono_class_is_abstract (klass)) {
2292 /* create trampolines for abstract methods */
2293 for (k = klass; k; k = k->parent) {
2295 gpointer iter = NULL;
2296 while ((m = mono_class_get_methods (k, &iter)))
2297 if (!pvt->vtable [m->slot]) {
2298 pvt->vtable [m->slot] = create_remoting_trampoline (domain, m, target_type, error);
2305 pvt->max_interface_id = max_interface_id;
2306 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2307 #ifdef COMPRESSED_INTERFACE_BITMAP
2308 bitmap = (uint8_t *)g_malloc0 (bsize);
2310 bitmap = (uint8_t *)mono_domain_alloc0 (domain, bsize);
2313 for (i = 0; i < klass->interface_offsets_count; ++i) {
2314 int interface_id = klass->interfaces_packed [i]->interface_id;
2315 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2318 if (extra_interfaces) {
2319 int slot = klass->vtable_size;
2325 /* Create trampolines for the methods of the interfaces */
2326 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2327 interf = (MonoClass *)list_item->data;
2329 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2333 while ((cm = mono_class_get_methods (interf, &iter))) {
2334 pvt->vtable [slot + j++] = create_remoting_trampoline (domain, cm, target_type, error);
2339 slot += mono_class_num_methods (interf);
2343 /* Now that the vtable is full, we can actually fill up the IMT */
2344 build_imt (klass, pvt, domain, interface_offsets, extra_interfaces);
2345 if (extra_interfaces) {
2346 g_slist_free (extra_interfaces);
2349 #ifdef COMPRESSED_INTERFACE_BITMAP
2350 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2351 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2352 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2355 pvt->interface_bitmap = bitmap;
2359 if (extra_interfaces)
2360 g_slist_free (extra_interfaces);
2361 #ifdef COMPRESSED_INTERFACE_BITMAP
2367 #endif /* DISABLE_REMOTING */
2370 * mono_class_field_is_special_static:
2372 * Returns whether @field is a thread/context static field.
2375 mono_class_field_is_special_static (MonoClassField *field)
2377 MONO_REQ_GC_NEUTRAL_MODE
2379 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2381 if (mono_field_is_deleted (field))
2383 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2384 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2391 * mono_class_field_get_special_static_type:
2392 * @field: The MonoClassField describing the field.
2394 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2395 * SPECIAL_STATIC_NONE otherwise.
2398 mono_class_field_get_special_static_type (MonoClassField *field)
2400 MONO_REQ_GC_NEUTRAL_MODE
2402 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2403 return SPECIAL_STATIC_NONE;
2404 if (mono_field_is_deleted (field))
2405 return SPECIAL_STATIC_NONE;
2406 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2407 return field_is_special_static (field->parent, field);
2408 return SPECIAL_STATIC_NONE;
2412 * mono_class_has_special_static_fields:
2414 * Returns whenever @klass has any thread/context static fields.
2417 mono_class_has_special_static_fields (MonoClass *klass)
2419 MONO_REQ_GC_NEUTRAL_MODE
2421 MonoClassField *field;
2425 while ((field = mono_class_get_fields (klass, &iter))) {
2426 g_assert (field->parent == klass);
2427 if (mono_class_field_is_special_static (field))
2434 #ifndef DISABLE_REMOTING
2436 * create_remote_class_key:
2437 * Creates an array of pointers that can be used as a hash key for a remote class.
2438 * The first element of the array is the number of pointers.
2441 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2443 MONO_REQ_GC_NEUTRAL_MODE;
2448 if (remote_class == NULL) {
2449 if (mono_class_is_interface (extra_class)) {
2450 key = (void **)g_malloc (sizeof(gpointer) * 3);
2451 key [0] = GINT_TO_POINTER (2);
2452 key [1] = mono_defaults.marshalbyrefobject_class;
2453 key [2] = extra_class;
2455 key = (void **)g_malloc (sizeof(gpointer) * 2);
2456 key [0] = GINT_TO_POINTER (1);
2457 key [1] = extra_class;
2460 if (extra_class != NULL && mono_class_is_interface (extra_class)) {
2461 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2462 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2463 key [1] = remote_class->proxy_class;
2465 // Keep the list of interfaces sorted
2466 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2467 if (extra_class && remote_class->interfaces [i] > extra_class) {
2468 key [j++] = extra_class;
2471 key [j] = remote_class->interfaces [i];
2474 key [j] = extra_class;
2476 // Replace the old class. The interface list is the same
2477 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2478 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2479 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2480 for (i = 0; i < remote_class->interface_count; i++)
2481 key [2 + i] = remote_class->interfaces [i];
2489 * copy_remote_class_key:
2491 * Make a copy of KEY in the domain and return the copy.
2494 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2496 MONO_REQ_GC_NEUTRAL_MODE
2498 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2499 gpointer *mp_key = (gpointer *)mono_domain_alloc (domain, key_size);
2501 memcpy (mp_key, key, key_size);
2507 * mono_remote_class:
2508 * @domain: the application domain
2509 * @class_name: name of the remote class
2510 * @error: set on error
2512 * Creates and initializes a MonoRemoteClass object for a remote type.
2514 * On failure returns NULL and sets @error
2517 mono_remote_class (MonoDomain *domain, MonoStringHandle class_name, MonoClass *proxy_class, MonoError *error)
2519 MONO_REQ_GC_UNSAFE_MODE;
2521 MonoRemoteClass *rc;
2522 gpointer* key, *mp_key;
2527 key = create_remote_class_key (NULL, proxy_class);
2529 mono_domain_lock (domain);
2530 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2534 mono_domain_unlock (domain);
2538 name = mono_string_to_utf8_mp (domain->mp, MONO_HANDLE_RAW (class_name), error);
2539 if (!is_ok (error)) {
2541 mono_domain_unlock (domain);
2545 mp_key = copy_remote_class_key (domain, key);
2549 if (mono_class_is_interface (proxy_class)) {
2550 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2551 rc->interface_count = 1;
2552 rc->interfaces [0] = proxy_class;
2553 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2555 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2556 rc->interface_count = 0;
2557 rc->proxy_class = proxy_class;
2560 rc->default_vtable = NULL;
2561 rc->xdomain_vtable = NULL;
2562 rc->proxy_class_name = name;
2563 #ifndef DISABLE_PERFCOUNTERS
2564 mono_perfcounters->loader_bytes += mono_string_length (MONO_HANDLE_RAW (class_name)) + 1;
2567 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2569 mono_domain_unlock (domain);
2574 * clone_remote_class:
2575 * Creates a copy of the remote_class, adding the provided class or interface
2577 static MonoRemoteClass*
2578 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2580 MONO_REQ_GC_NEUTRAL_MODE;
2582 MonoRemoteClass *rc;
2583 gpointer* key, *mp_key;
2585 key = create_remote_class_key (remote_class, extra_class);
2586 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2592 mp_key = copy_remote_class_key (domain, key);
2596 if (mono_class_is_interface (extra_class)) {
2598 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2599 rc->proxy_class = remote_class->proxy_class;
2600 rc->interface_count = remote_class->interface_count + 1;
2602 // Keep the list of interfaces sorted, since the hash key of
2603 // the remote class depends on this
2604 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2605 if (remote_class->interfaces [i] > extra_class && i == j)
2606 rc->interfaces [j++] = extra_class;
2607 rc->interfaces [j] = remote_class->interfaces [i];
2610 rc->interfaces [j] = extra_class;
2612 // Replace the old class. The interface array is the same
2613 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2614 rc->proxy_class = extra_class;
2615 rc->interface_count = remote_class->interface_count;
2616 if (rc->interface_count > 0)
2617 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2620 rc->default_vtable = NULL;
2621 rc->xdomain_vtable = NULL;
2622 rc->proxy_class_name = remote_class->proxy_class_name;
2624 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2630 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxyHandle rp, MonoError *error)
2632 MONO_REQ_GC_UNSAFE_MODE;
2636 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2637 mono_domain_lock (domain);
2638 gint32 target_domain_id = MONO_HANDLE_GETVAL (rp, target_domain_id);
2639 if (target_domain_id != -1) {
2640 if (remote_class->xdomain_vtable == NULL)
2641 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN, error);
2642 mono_domain_unlock (domain);
2643 mono_loader_unlock ();
2644 return_val_if_nok (error, NULL);
2645 return remote_class->xdomain_vtable;
2647 if (remote_class->default_vtable == NULL) {
2648 MonoReflectionTypeHandle reftype = MONO_HANDLE_NEW (MonoReflectionType, NULL);
2649 MONO_HANDLE_GET (reftype, rp, class_to_proxy);
2651 MonoType *type = MONO_HANDLE_GETVAL (reftype, type);
2652 MonoClass *klass = mono_class_from_mono_type (type);
2654 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)))
2655 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP, error);
2658 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN, error);
2659 /* N.B. both branches of the if modify error */
2660 if (!is_ok (error)) {
2661 mono_domain_unlock (domain);
2662 mono_loader_unlock ();
2667 mono_domain_unlock (domain);
2668 mono_loader_unlock ();
2669 return remote_class->default_vtable;
2673 * mono_upgrade_remote_class:
2674 * @domain: the application domain
2675 * @tproxy: the proxy whose remote class has to be upgraded.
2676 * @klass: class to which the remote class can be casted.
2677 * @error: set on error
2679 * Updates the vtable of the remote class by adding the necessary method slots
2680 * and interface offsets so it can be safely casted to klass. klass can be a
2681 * class or an interface. On success returns TRUE, on failure returns FALSE and sets @error.
2684 mono_upgrade_remote_class (MonoDomain *domain, MonoObjectHandle proxy_object, MonoClass *klass, MonoError *error)
2686 MONO_REQ_GC_UNSAFE_MODE;
2690 MonoTransparentProxyHandle tproxy = MONO_HANDLE_CAST (MonoTransparentProxy, proxy_object);
2691 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (tproxy, remote_class);
2693 gboolean redo_vtable;
2694 if (mono_class_is_interface (klass)) {
2697 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2698 if (remote_class->interfaces [i] == klass)
2699 redo_vtable = FALSE;
2702 redo_vtable = (remote_class->proxy_class != klass);
2705 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2706 mono_domain_lock (domain);
2708 MonoRemoteClass *fresh_remote_class = clone_remote_class (domain, remote_class, klass);
2709 MONO_HANDLE_SETVAL (tproxy, remote_class, MonoRemoteClass*, fresh_remote_class);
2710 MonoRealProxyHandle real_proxy = MONO_HANDLE_NEW (MonoRealProxy, NULL);
2711 MONO_HANDLE_GET (real_proxy, tproxy, rp);
2712 MONO_HANDLE_SETVAL (proxy_object, vtable, MonoVTable*, mono_remote_class_vtable (domain, fresh_remote_class, real_proxy, error));
2718 mono_domain_unlock (domain);
2719 mono_loader_unlock ();
2720 return is_ok (error);
2722 #endif /* DISABLE_REMOTING */
2726 * mono_object_get_virtual_method:
2727 * @obj: object to operate on.
2730 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2731 * the instance of a callvirt of method.
2734 mono_object_get_virtual_method (MonoObject *obj_raw, MonoMethod *method)
2736 MONO_REQ_GC_UNSAFE_MODE;
2737 HANDLE_FUNCTION_ENTER ();
2739 MONO_HANDLE_DCL (MonoObject, obj);
2740 MonoMethod *result = mono_object_handle_get_virtual_method (obj, method, &error);
2741 mono_error_assert_ok (&error);
2742 HANDLE_FUNCTION_RETURN_VAL (result);
2746 * mono_object_get_virtual_method:
2747 * @obj: object to operate on.
2750 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2751 * the instance of a callvirt of method.
2754 mono_object_handle_get_virtual_method (MonoObjectHandle obj, MonoMethod *method, MonoError *error)
2758 gboolean is_proxy = FALSE;
2759 MonoClass *klass = mono_handle_class (obj);
2760 if (mono_class_is_transparent_proxy (klass)) {
2761 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), remote_class);
2762 klass = remote_class->proxy_class;
2765 return class_get_virtual_method (klass, method, is_proxy, error);
2769 class_get_virtual_method (MonoClass *klass, MonoMethod *method, gboolean is_proxy, MonoError *error)
2774 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2777 mono_class_setup_vtable (klass);
2778 MonoMethod **vtable = klass->vtable;
2780 if (method->slot == -1) {
2781 /* method->slot might not be set for instances of generic methods */
2782 if (method->is_inflated) {
2783 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2784 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2787 g_assert_not_reached ();
2791 MonoMethod *res = NULL;
2792 /* check method->slot is a valid index: perform isinstance? */
2793 if (method->slot != -1) {
2794 if (mono_class_is_interface (method->klass)) {
2796 gboolean variance_used = FALSE;
2797 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2798 g_assert (iface_offset > 0);
2799 res = vtable [iface_offset + method->slot];
2802 res = vtable [method->slot];
2806 #ifndef DISABLE_REMOTING
2808 /* It may be an interface, abstract class method or generic method */
2809 if (!res || mono_method_signature (res)->generic_param_count)
2812 /* generic methods demand invoke_with_check */
2813 if (mono_method_signature (res)->generic_param_count)
2814 res = mono_marshal_get_remoting_invoke_with_check (res);
2817 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2818 res = mono_cominterop_get_invoke (res);
2821 res = mono_marshal_get_remoting_invoke (res);
2826 if (method->is_inflated) {
2827 /* Have to inflate the result */
2828 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, error);
2836 do_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2838 MONO_REQ_GC_UNSAFE_MODE;
2840 MonoObject *result = NULL;
2842 g_assert (callbacks.runtime_invoke);
2846 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2847 mono_profiler_method_start_invoke (method);
2849 result = callbacks.runtime_invoke (method, obj, params, exc, error);
2851 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2852 mono_profiler_method_end_invoke (method);
2854 if (!mono_error_ok (error))
2861 * mono_runtime_invoke:
2862 * @method: method to invoke
2863 * @obJ: object instance
2864 * @params: arguments to the method
2865 * @exc: exception information.
2867 * Invokes the method represented by @method on the object @obj.
2869 * obj is the 'this' pointer, it should be NULL for static
2870 * methods, a MonoObject* for object instances and a pointer to
2871 * the value type for value types.
2873 * The params array contains the arguments to the method with the
2874 * same convention: MonoObject* pointers for object instances and
2875 * pointers to the value type otherwise.
2877 * From unmanaged code you'll usually use the
2878 * mono_runtime_invoke() variant.
2880 * Note that this function doesn't handle virtual methods for
2881 * you, it will exec the exact method you pass: we still need to
2882 * expose a function to lookup the derived class implementation
2883 * of a virtual method (there are examples of this in the code,
2886 * You can pass NULL as the exc argument if you don't want to
2887 * catch exceptions, otherwise, *exc will be set to the exception
2888 * thrown, if any. if an exception is thrown, you can't use the
2889 * MonoObject* result from the function.
2891 * If the method returns a value type, it is boxed in an object
2895 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2900 res = mono_runtime_try_invoke (method, obj, params, exc, &error);
2901 if (*exc == NULL && !mono_error_ok(&error)) {
2902 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
2904 mono_error_cleanup (&error);
2906 res = mono_runtime_invoke_checked (method, obj, params, &error);
2907 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
2913 * mono_runtime_try_invoke:
2914 * @method: method to invoke
2915 * @obJ: object instance
2916 * @params: arguments to the method
2917 * @exc: exception information.
2918 * @error: set on error
2920 * Invokes the method represented by @method on the object @obj.
2922 * obj is the 'this' pointer, it should be NULL for static
2923 * methods, a MonoObject* for object instances and a pointer to
2924 * the value type for value types.
2926 * The params array contains the arguments to the method with the
2927 * same convention: MonoObject* pointers for object instances and
2928 * pointers to the value type otherwise.
2930 * From unmanaged code you'll usually use the
2931 * mono_runtime_invoke() variant.
2933 * Note that this function doesn't handle virtual methods for
2934 * you, it will exec the exact method you pass: we still need to
2935 * expose a function to lookup the derived class implementation
2936 * of a virtual method (there are examples of this in the code,
2939 * For this function, you must not pass NULL as the exc argument if
2940 * you don't want to catch exceptions, use
2941 * mono_runtime_invoke_checked(). If an exception is thrown, you
2942 * can't use the MonoObject* result from the function.
2944 * If this method cannot be invoked, @error will be set and @exc and
2945 * the return value must not be used.
2947 * If the method returns a value type, it is boxed in an object
2951 mono_runtime_try_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError* error)
2953 MONO_REQ_GC_UNSAFE_MODE;
2955 g_assert (exc != NULL);
2957 if (mono_runtime_get_no_exec ())
2958 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2960 return do_runtime_invoke (method, obj, params, exc, error);
2964 * mono_runtime_invoke_checked:
2965 * @method: method to invoke
2966 * @obJ: object instance
2967 * @params: arguments to the method
2968 * @error: set on error
2970 * Invokes the method represented by @method on the object @obj.
2972 * obj is the 'this' pointer, it should be NULL for static
2973 * methods, a MonoObject* for object instances and a pointer to
2974 * the value type for value types.
2976 * The params array contains the arguments to the method with the
2977 * same convention: MonoObject* pointers for object instances and
2978 * pointers to the value type otherwise.
2980 * From unmanaged code you'll usually use the
2981 * mono_runtime_invoke() variant.
2983 * Note that this function doesn't handle virtual methods for
2984 * you, it will exec the exact method you pass: we still need to
2985 * expose a function to lookup the derived class implementation
2986 * of a virtual method (there are examples of this in the code,
2989 * If an exception is thrown, you can't use the MonoObject* result
2990 * from the function.
2992 * If this method cannot be invoked, @error will be set. If the
2993 * method throws an exception (and we're in coop mode) the exception
2994 * will be set in @error.
2996 * If the method returns a value type, it is boxed in an object
3000 mono_runtime_invoke_checked (MonoMethod *method, void *obj, void **params, MonoError* error)
3002 MONO_REQ_GC_UNSAFE_MODE;
3004 if (mono_runtime_get_no_exec ())
3005 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
3007 return do_runtime_invoke (method, obj, params, NULL, error);
3011 * mono_method_get_unmanaged_thunk:
3012 * @method: method to generate a thunk for.
3014 * Returns an unmanaged->managed thunk that can be used to call
3015 * a managed method directly from C.
3017 * The thunk's C signature closely matches the managed signature:
3019 * C#: public bool Equals (object obj);
3020 * C: typedef MonoBoolean (*Equals)(MonoObject*,
3021 * MonoObject*, MonoException**);
3023 * The 1st ("this") parameter must not be used with static methods:
3025 * C#: public static bool ReferenceEquals (object a, object b);
3026 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
3029 * The last argument must be a non-null pointer of a MonoException* pointer.
3030 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
3031 * exception has been thrown in managed code. Otherwise it will point
3032 * to the MonoException* caught by the thunk. In this case, the result of
3033 * the thunk is undefined:
3035 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
3036 * MonoException *ex = NULL;
3037 * Equals func = mono_method_get_unmanaged_thunk (method);
3038 * MonoBoolean res = func (thisObj, objToCompare, &ex);
3040 * // handle exception
3043 * The calling convention of the thunk matches the platform's default
3044 * convention. This means that under Windows, C declarations must
3045 * contain the __stdcall attribute:
3047 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
3048 * MonoObject*, MonoException**);
3052 * Value type arguments and return values are treated as they were objects:
3054 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
3055 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
3057 * Arguments must be properly boxed upon trunk's invocation, while return
3058 * values must be unboxed.
3061 mono_method_get_unmanaged_thunk (MonoMethod *method)
3063 MONO_REQ_GC_NEUTRAL_MODE;
3064 MONO_REQ_API_ENTRYPOINT;
3069 g_assert (!mono_threads_is_coop_enabled ());
3071 MONO_ENTER_GC_UNSAFE;
3072 method = mono_marshal_get_thunk_invoke_wrapper (method);
3073 res = mono_compile_method_checked (method, &error);
3074 mono_error_cleanup (&error);
3075 MONO_EXIT_GC_UNSAFE;
3081 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
3083 MONO_REQ_GC_UNSAFE_MODE;
3087 /* object fields cannot be byref, so we don't need a
3089 gpointer *p = (gpointer*)dest;
3096 case MONO_TYPE_BOOLEAN:
3098 case MONO_TYPE_U1: {
3099 guint8 *p = (guint8*)dest;
3100 *p = value ? *(guint8*)value : 0;
3105 case MONO_TYPE_CHAR: {
3106 guint16 *p = (guint16*)dest;
3107 *p = value ? *(guint16*)value : 0;
3110 #if SIZEOF_VOID_P == 4
3115 case MONO_TYPE_U4: {
3116 gint32 *p = (gint32*)dest;
3117 *p = value ? *(gint32*)value : 0;
3120 #if SIZEOF_VOID_P == 8
3125 case MONO_TYPE_U8: {
3126 gint64 *p = (gint64*)dest;
3127 *p = value ? *(gint64*)value : 0;
3130 case MONO_TYPE_R4: {
3131 float *p = (float*)dest;
3132 *p = value ? *(float*)value : 0;
3135 case MONO_TYPE_R8: {
3136 double *p = (double*)dest;
3137 *p = value ? *(double*)value : 0;
3140 case MONO_TYPE_STRING:
3141 case MONO_TYPE_SZARRAY:
3142 case MONO_TYPE_CLASS:
3143 case MONO_TYPE_OBJECT:
3144 case MONO_TYPE_ARRAY:
3145 mono_gc_wbarrier_generic_store (dest, deref_pointer ? *(MonoObject **)value : (MonoObject *)value);
3147 case MONO_TYPE_FNPTR:
3148 case MONO_TYPE_PTR: {
3149 gpointer *p = (gpointer*)dest;
3150 *p = deref_pointer? *(gpointer*)value: value;
3153 case MONO_TYPE_VALUETYPE:
3154 /* note that 't' and 'type->type' can be different */
3155 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3156 t = mono_class_enum_basetype (type->data.klass)->type;
3159 MonoClass *klass = mono_class_from_mono_type (type);
3160 int size = mono_class_value_size (klass, NULL);
3162 mono_gc_bzero_atomic (dest, size);
3164 mono_gc_wbarrier_value_copy (dest, value, 1, klass);
3167 case MONO_TYPE_GENERICINST:
3168 t = type->data.generic_class->container_class->byval_arg.type;
3171 g_error ("got type %x", type->type);
3176 * mono_field_set_value:
3177 * @obj: Instance object
3178 * @field: MonoClassField describing the field to set
3179 * @value: The value to be set
3181 * Sets the value of the field described by @field in the object instance @obj
3182 * to the value passed in @value. This method should only be used for instance
3183 * fields. For static fields, use mono_field_static_set_value.
3185 * The value must be on the native format of the field type.
3188 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3190 MONO_REQ_GC_UNSAFE_MODE;
3194 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3196 dest = (char*)obj + field->offset;
3197 mono_copy_value (field->type, dest, value, FALSE);
3201 * mono_field_static_set_value:
3202 * @field: MonoClassField describing the field to set
3203 * @value: The value to be set
3205 * Sets the value of the static field described by @field
3206 * to the value passed in @value.
3208 * The value must be on the native format of the field type.
3211 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3213 MONO_REQ_GC_UNSAFE_MODE;
3217 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3218 /* you cant set a constant! */
3219 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3221 if (field->offset == -1) {
3222 /* Special static */
3225 mono_domain_lock (vt->domain);
3226 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3227 mono_domain_unlock (vt->domain);
3228 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3230 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3232 mono_copy_value (field->type, dest, value, FALSE);
3236 * mono_vtable_get_static_field_data:
3238 * Internal use function: return a pointer to the memory holding the static fields
3239 * for a class or NULL if there are no static fields.
3240 * This is exported only for use by the debugger.
3243 mono_vtable_get_static_field_data (MonoVTable *vt)
3245 MONO_REQ_GC_NEUTRAL_MODE
3247 if (!vt->has_static_fields)
3249 return vt->vtable [vt->klass->vtable_size];
3253 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3255 MONO_REQ_GC_UNSAFE_MODE;
3259 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3260 if (field->offset == -1) {
3261 /* Special static */
3264 mono_domain_lock (vt->domain);
3265 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3266 mono_domain_unlock (vt->domain);
3267 src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3269 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3272 src = (guint8*)obj + field->offset;
3279 * mono_field_get_value:
3280 * @obj: Object instance
3281 * @field: MonoClassField describing the field to fetch information from
3282 * @value: pointer to the location where the value will be stored
3284 * Use this routine to get the value of the field @field in the object
3287 * The pointer provided by value must be of the field type, for reference
3288 * types this is a MonoObject*, for value types its the actual pointer to
3293 * mono_field_get_value (obj, int_field, &i);
3296 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3298 MONO_REQ_GC_UNSAFE_MODE;
3304 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3306 src = (char*)obj + field->offset;
3307 mono_copy_value (field->type, value, src, TRUE);
3311 * mono_field_get_value_object:
3312 * @domain: domain where the object will be created (if boxing)
3313 * @field: MonoClassField describing the field to fetch information from
3314 * @obj: The object instance for the field.
3316 * Returns: a new MonoObject with the value from the given field. If the
3317 * field represents a value type, the value is boxed.
3321 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3324 MonoObject* result = mono_field_get_value_object_checked (domain, field, obj, &error);
3325 mono_error_assert_ok (&error);
3330 * mono_field_get_value_object_checked:
3331 * @domain: domain where the object will be created (if boxing)
3332 * @field: MonoClassField describing the field to fetch information from
3333 * @obj: The object instance for the field.
3334 * @error: Set on error.
3336 * Returns: a new MonoObject with the value from the given field. If the
3337 * field represents a value type, the value is boxed. On error returns NULL and sets @error.
3341 mono_field_get_value_object_checked (MonoDomain *domain, MonoClassField *field, MonoObject *obj, MonoError *error)
3343 MONO_REQ_GC_UNSAFE_MODE;
3349 MonoVTable *vtable = NULL;
3351 gboolean is_static = FALSE;
3352 gboolean is_ref = FALSE;
3353 gboolean is_literal = FALSE;
3354 gboolean is_ptr = FALSE;
3355 MonoType *type = mono_field_get_type_checked (field, error);
3357 return_val_if_nok (error, NULL);
3359 switch (type->type) {
3360 case MONO_TYPE_STRING:
3361 case MONO_TYPE_OBJECT:
3362 case MONO_TYPE_CLASS:
3363 case MONO_TYPE_ARRAY:
3364 case MONO_TYPE_SZARRAY:
3369 case MONO_TYPE_BOOLEAN:
3372 case MONO_TYPE_CHAR:
3381 case MONO_TYPE_VALUETYPE:
3382 is_ref = type->byref;
3384 case MONO_TYPE_GENERICINST:
3385 is_ref = !mono_type_generic_inst_is_valuetype (type);
3391 g_error ("type 0x%x not handled in "
3392 "mono_field_get_value_object", type->type);
3396 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3399 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3403 vtable = mono_class_vtable_full (domain, field->parent, error);
3404 return_val_if_nok (error, NULL);
3406 if (!vtable->initialized) {
3407 mono_runtime_class_init_full (vtable, error);
3408 return_val_if_nok (error, NULL);
3417 get_default_field_value (domain, field, &o, error);
3418 return_val_if_nok (error, NULL);
3419 } else if (is_static) {
3420 mono_field_static_get_value_checked (vtable, field, &o, error);
3421 return_val_if_nok (error, NULL);
3423 mono_field_get_value (obj, field, &o);
3429 static MonoMethod *m;
3435 MonoClass *ptr_klass = mono_class_get_pointer_class ();
3436 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3442 get_default_field_value (domain, field, v, error);
3443 return_val_if_nok (error, NULL);
3444 } else if (is_static) {
3445 mono_field_static_get_value_checked (vtable, field, v, error);
3446 return_val_if_nok (error, NULL);
3448 mono_field_get_value (obj, field, v);
3451 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3452 args [0] = ptr ? *ptr : NULL;
3453 args [1] = mono_type_get_object_checked (mono_domain_get (), type, error);
3454 return_val_if_nok (error, NULL);
3456 o = mono_runtime_invoke_checked (m, NULL, args, error);
3457 return_val_if_nok (error, NULL);
3462 /* boxed value type */
3463 klass = mono_class_from_mono_type (type);
3465 if (mono_class_is_nullable (klass))
3466 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass, error);
3468 o = mono_object_new_checked (domain, klass, error);
3469 return_val_if_nok (error, NULL);
3470 v = ((gchar *) o) + sizeof (MonoObject);
3473 get_default_field_value (domain, field, v, error);
3474 return_val_if_nok (error, NULL);
3475 } else if (is_static) {
3476 mono_field_static_get_value_checked (vtable, field, v, error);
3477 return_val_if_nok (error, NULL);
3479 mono_field_get_value (obj, field, v);
3486 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value, MonoError *error)
3488 MONO_REQ_GC_UNSAFE_MODE;
3492 const char *p = blob;
3493 mono_metadata_decode_blob_size (p, &p);
3496 case MONO_TYPE_BOOLEAN:
3499 *(guint8 *) value = *p;
3501 case MONO_TYPE_CHAR:
3504 *(guint16*) value = read16 (p);
3508 *(guint32*) value = read32 (p);
3512 *(guint64*) value = read64 (p);
3515 readr4 (p, (float*) value);
3518 readr8 (p, (double*) value);
3520 case MONO_TYPE_STRING:
3521 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob, error);
3523 case MONO_TYPE_CLASS:
3524 *(gpointer*) value = NULL;
3528 g_warning ("type 0x%02x should not be in constant table", type);
3534 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error)
3536 MONO_REQ_GC_NEUTRAL_MODE;
3538 MonoTypeEnum def_type;
3543 data = mono_class_get_field_default_value (field, &def_type);
3544 mono_get_constant_value_from_blob (domain, def_type, data, value, error);
3548 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3550 MONO_REQ_GC_UNSAFE_MODE;
3556 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3558 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3559 get_default_field_value (vt->domain, field, value, error);
3563 if (field->offset == -1) {
3564 /* Special static */
3565 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3566 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3568 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3570 mono_copy_value (field->type, value, src, TRUE);
3574 * mono_field_static_get_value:
3575 * @vt: vtable to the object
3576 * @field: MonoClassField describing the field to fetch information from
3577 * @value: where the value is returned
3579 * Use this routine to get the value of the static field @field value.
3581 * The pointer provided by value must be of the field type, for reference
3582 * types this is a MonoObject*, for value types its the actual pointer to
3587 * mono_field_static_get_value (vt, int_field, &i);
3590 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3592 MONO_REQ_GC_NEUTRAL_MODE;
3595 mono_field_static_get_value_checked (vt, field, value, &error);
3596 mono_error_cleanup (&error);
3600 * mono_field_static_get_value_checked:
3601 * @vt: vtable to the object
3602 * @field: MonoClassField describing the field to fetch information from
3603 * @value: where the value is returned
3604 * @error: set on error
3606 * Use this routine to get the value of the static field @field value.
3608 * The pointer provided by value must be of the field type, for reference
3609 * types this is a MonoObject*, for value types its the actual pointer to
3614 * mono_field_static_get_value_checked (vt, int_field, &i, error);
3615 * if (!is_ok (error)) { ... }
3617 * On failure sets @error.
3620 mono_field_static_get_value_checked (MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3622 MONO_REQ_GC_NEUTRAL_MODE;
3624 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value, error);
3628 * mono_property_set_value:
3629 * @prop: MonoProperty to set
3630 * @obj: instance object on which to act
3631 * @params: parameters to pass to the propery
3632 * @exc: optional exception
3634 * Invokes the property's set method with the given arguments on the
3635 * object instance obj (or NULL for static properties).
3637 * You can pass NULL as the exc argument if you don't want to
3638 * catch exceptions, otherwise, *exc will be set to the exception
3639 * thrown, if any. if an exception is thrown, you can't use the
3640 * MonoObject* result from the function.
3643 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3645 MONO_REQ_GC_UNSAFE_MODE;
3648 do_runtime_invoke (prop->set, obj, params, exc, &error);
3649 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3650 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3652 mono_error_cleanup (&error);
3657 * mono_property_set_value_checked:
3658 * @prop: MonoProperty to set
3659 * @obj: instance object on which to act
3660 * @params: parameters to pass to the propery
3661 * @error: set on error
3663 * Invokes the property's set method with the given arguments on the
3664 * object instance obj (or NULL for static properties).
3666 * Returns: TRUE on success. On failure returns FALSE and sets @error.
3667 * If an exception is thrown, it will be caught and returned via @error.
3670 mono_property_set_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3672 MONO_REQ_GC_UNSAFE_MODE;
3677 do_runtime_invoke (prop->set, obj, params, &exc, error);
3678 if (exc != NULL && is_ok (error))
3679 mono_error_set_exception_instance (error, (MonoException*)exc);
3680 return is_ok (error);
3684 * mono_property_get_value:
3685 * @prop: MonoProperty to fetch
3686 * @obj: instance object on which to act
3687 * @params: parameters to pass to the propery
3688 * @exc: optional exception
3690 * Invokes the property's get method with the given arguments on the
3691 * object instance obj (or NULL for static properties).
3693 * You can pass NULL as the exc argument if you don't want to
3694 * catch exceptions, otherwise, *exc will be set to the exception
3695 * thrown, if any. if an exception is thrown, you can't use the
3696 * MonoObject* result from the function.
3698 * Returns: the value from invoking the get method on the property.
3701 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3703 MONO_REQ_GC_UNSAFE_MODE;
3706 MonoObject *val = do_runtime_invoke (prop->get, obj, params, exc, &error);
3707 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3708 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3710 mono_error_cleanup (&error); /* FIXME don't raise here */
3717 * mono_property_get_value_checked:
3718 * @prop: MonoProperty to fetch
3719 * @obj: instance object on which to act
3720 * @params: parameters to pass to the propery
3721 * @error: set on error
3723 * Invokes the property's get method with the given arguments on the
3724 * object instance obj (or NULL for static properties).
3726 * If an exception is thrown, you can't use the
3727 * MonoObject* result from the function. The exception will be propagated via @error.
3729 * Returns: the value from invoking the get method on the property. On
3730 * failure returns NULL and sets @error.
3733 mono_property_get_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3735 MONO_REQ_GC_UNSAFE_MODE;
3738 MonoObject *val = do_runtime_invoke (prop->get, obj, params, &exc, error);
3739 if (exc != NULL && !is_ok (error))
3740 mono_error_set_exception_instance (error, (MonoException*) exc);
3748 * mono_nullable_init:
3749 * @buf: The nullable structure to initialize.
3750 * @value: the value to initialize from
3751 * @klass: the type for the object
3753 * Initialize the nullable structure pointed to by @buf from @value which
3754 * should be a boxed value type. The size of @buf should be able to hold
3755 * as much data as the @klass->instance_size (which is the number of bytes
3756 * that will be copies).
3758 * Since Nullables have variable structure, we can not define a C
3759 * structure for them.
3762 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3764 MONO_REQ_GC_UNSAFE_MODE;
3766 MonoClass *param_class = klass->cast_class;
3768 mono_class_setup_fields (klass);
3769 g_assert (klass->fields_inited);
3771 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3772 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3774 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3776 if (param_class->has_references)
3777 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3779 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3781 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3786 * mono_nullable_box:
3787 * @buf: The buffer representing the data to be boxed
3788 * @klass: the type to box it as.
3789 * @error: set on oerr
3791 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3792 * @buf. On failure returns NULL and sets @error
3795 mono_nullable_box (guint8 *buf, MonoClass *klass, MonoError *error)
3797 MONO_REQ_GC_UNSAFE_MODE;
3800 MonoClass *param_class = klass->cast_class;
3802 mono_class_setup_fields (klass);
3803 g_assert (klass->fields_inited);
3805 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3806 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3808 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3809 MonoObject *o = mono_object_new_checked (mono_domain_get (), param_class, error);
3810 return_val_if_nok (error, NULL);
3811 if (param_class->has_references)
3812 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3814 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3822 * mono_get_delegate_invoke:
3823 * @klass: The delegate class
3825 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3828 mono_get_delegate_invoke (MonoClass *klass)
3830 MONO_REQ_GC_NEUTRAL_MODE;
3834 /* This is called at runtime, so avoid the slower search in metadata */
3835 mono_class_setup_methods (klass);
3836 if (mono_class_has_failure (klass))
3838 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3843 * mono_get_delegate_begin_invoke:
3844 * @klass: The delegate class
3846 * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3849 mono_get_delegate_begin_invoke (MonoClass *klass)
3851 MONO_REQ_GC_NEUTRAL_MODE;
3855 /* This is called at runtime, so avoid the slower search in metadata */
3856 mono_class_setup_methods (klass);
3857 if (mono_class_has_failure (klass))
3859 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3864 * mono_get_delegate_end_invoke:
3865 * @klass: The delegate class
3867 * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3870 mono_get_delegate_end_invoke (MonoClass *klass)
3872 MONO_REQ_GC_NEUTRAL_MODE;
3876 /* This is called at runtime, so avoid the slower search in metadata */
3877 mono_class_setup_methods (klass);
3878 if (mono_class_has_failure (klass))
3880 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3885 * mono_runtime_delegate_invoke:
3886 * @delegate: pointer to a delegate object.
3887 * @params: parameters for the delegate.
3888 * @exc: Pointer to the exception result.
3890 * Invokes the delegate method @delegate with the parameters provided.
3892 * You can pass NULL as the exc argument if you don't want to
3893 * catch exceptions, otherwise, *exc will be set to the exception
3894 * thrown, if any. if an exception is thrown, you can't use the
3895 * MonoObject* result from the function.
3898 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3900 MONO_REQ_GC_UNSAFE_MODE;
3904 MonoObject *result = mono_runtime_delegate_try_invoke (delegate, params, exc, &error);
3906 mono_error_cleanup (&error);
3909 if (!is_ok (&error))
3910 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
3914 MonoObject *result = mono_runtime_delegate_invoke_checked (delegate, params, &error);
3915 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
3921 * mono_runtime_delegate_try_invoke:
3922 * @delegate: pointer to a delegate object.
3923 * @params: parameters for the delegate.
3924 * @exc: Pointer to the exception result.
3925 * @error: set on error
3927 * Invokes the delegate method @delegate with the parameters provided.
3929 * You can pass NULL as the exc argument if you don't want to
3930 * catch exceptions, otherwise, *exc will be set to the exception
3931 * thrown, if any. On failure to execute, @error will be set.
3932 * if an exception is thrown, you can't use the
3933 * MonoObject* result from the function.
3936 mono_runtime_delegate_try_invoke (MonoObject *delegate, void **params, MonoObject **exc, MonoError *error)
3938 MONO_REQ_GC_UNSAFE_MODE;
3942 MonoClass *klass = delegate->vtable->klass;
3945 im = mono_get_delegate_invoke (klass);
3947 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3950 o = mono_runtime_try_invoke (im, delegate, params, exc, error);
3952 o = mono_runtime_invoke_checked (im, delegate, params, error);
3959 * mono_runtime_delegate_invoke_checked:
3960 * @delegate: pointer to a delegate object.
3961 * @params: parameters for the delegate.
3962 * @error: set on error
3964 * Invokes the delegate method @delegate with the parameters provided.
3966 * On failure @error will be set and you can't use the MonoObject*
3967 * result from the function.
3970 mono_runtime_delegate_invoke_checked (MonoObject *delegate, void **params, MonoError *error)
3973 return mono_runtime_delegate_try_invoke (delegate, params, NULL, error);
3976 static char **main_args = NULL;
3977 static int num_main_args = 0;
3980 * mono_runtime_get_main_args:
3982 * Returns: a MonoArray with the arguments passed to the main program
3985 mono_runtime_get_main_args (void)
3987 MONO_REQ_GC_UNSAFE_MODE;
3989 MonoArray *result = mono_runtime_get_main_args_checked (&error);
3990 mono_error_assert_ok (&error);
3995 * mono_runtime_get_main_args:
3996 * @error: set on error
3998 * Returns: a MonoArray with the arguments passed to the main
3999 * program. On failure returns NULL and sets @error.
4002 mono_runtime_get_main_args_checked (MonoError *error)
4006 MonoDomain *domain = mono_domain_get ();
4010 res = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, num_main_args, error);
4011 return_val_if_nok (error, NULL);
4013 for (i = 0; i < num_main_args; ++i)
4014 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
4020 free_main_args (void)
4022 MONO_REQ_GC_NEUTRAL_MODE;
4026 for (i = 0; i < num_main_args; ++i)
4027 g_free (main_args [i]);
4034 * mono_runtime_set_main_args:
4035 * @argc: number of arguments from the command line
4036 * @argv: array of strings from the command line
4038 * Set the command line arguments from an embedding application that doesn't otherwise call
4039 * mono_runtime_run_main ().
4042 mono_runtime_set_main_args (int argc, char* argv[])
4044 MONO_REQ_GC_NEUTRAL_MODE;
4049 main_args = g_new0 (char*, argc);
4050 num_main_args = argc;
4052 for (i = 0; i < argc; ++i) {
4055 utf8_arg = mono_utf8_from_external (argv[i]);
4056 if (utf8_arg == NULL) {
4057 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
4058 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4062 main_args [i] = utf8_arg;
4069 * Prepare an array of arguments in order to execute a standard Main()
4070 * method (argc/argv contains the executable name). This method also
4071 * sets the command line argument value needed by System.Environment.
4075 prepare_run_main (MonoMethod *method, int argc, char *argv[])
4077 MONO_REQ_GC_UNSAFE_MODE;
4081 MonoArray *args = NULL;
4082 MonoDomain *domain = mono_domain_get ();
4083 gchar *utf8_fullpath;
4084 MonoMethodSignature *sig;
4086 g_assert (method != NULL);
4088 mono_thread_set_main (mono_thread_current ());
4090 main_args = g_new0 (char*, argc);
4091 num_main_args = argc;
4093 if (!g_path_is_absolute (argv [0])) {
4094 gchar *basename = g_path_get_basename (argv [0]);
4095 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
4099 utf8_fullpath = mono_utf8_from_external (fullpath);
4100 if(utf8_fullpath == NULL) {
4101 /* Printing the arg text will cause glib to
4102 * whinge about "Invalid UTF-8", but at least
4103 * its relevant, and shows the problem text
4106 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
4107 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4114 utf8_fullpath = mono_utf8_from_external (argv[0]);
4115 if(utf8_fullpath == NULL) {
4116 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
4117 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4122 main_args [0] = utf8_fullpath;
4124 for (i = 1; i < argc; ++i) {
4127 utf8_arg=mono_utf8_from_external (argv[i]);
4128 if(utf8_arg==NULL) {
4129 /* Ditto the comment about Invalid UTF-8 here */
4130 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
4131 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4135 main_args [i] = utf8_arg;
4140 sig = mono_method_signature (method);
4142 g_print ("Unable to load Main method.\n");
4146 if (sig->param_count) {
4147 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, argc, &error);
4148 mono_error_assert_ok (&error);
4149 for (i = 0; i < argc; ++i) {
4150 /* The encodings should all work, given that
4151 * we've checked all these args for the
4154 gchar *str = mono_utf8_from_external (argv [i]);
4155 MonoString *arg = mono_string_new (domain, str);
4156 mono_array_setref (args, i, arg);
4160 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, 0, &error);
4161 mono_error_assert_ok (&error);
4164 mono_assembly_set_main (method->klass->image->assembly);
4170 * mono_runtime_run_main:
4171 * @method: the method to start the application with (usually Main)
4172 * @argc: number of arguments from the command line
4173 * @argv: array of strings from the command line
4174 * @exc: excetption results
4176 * Execute a standard Main() method (argc/argv contains the
4177 * executable name). This method also sets the command line argument value
4178 * needed by System.Environment.
4183 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
4186 MONO_REQ_GC_UNSAFE_MODE;
4189 MonoArray *args = prepare_run_main (method, argc, argv);
4192 res = mono_runtime_try_exec_main (method, args, exc);
4194 res = mono_runtime_exec_main_checked (method, args, &error);
4195 mono_error_raise_exception (&error); /* OK to throw, external only without a better alternative */
4201 * mono_runtime_run_main_checked:
4202 * @method: the method to start the application with (usually Main)
4203 * @argc: number of arguments from the command line
4204 * @argv: array of strings from the command line
4205 * @error: set on error
4207 * Execute a standard Main() method (argc/argv contains the
4208 * executable name). This method also sets the command line argument value
4209 * needed by System.Environment. On failure sets @error.
4214 mono_runtime_run_main_checked (MonoMethod *method, int argc, char* argv[],
4218 MonoArray *args = prepare_run_main (method, argc, argv);
4219 return mono_runtime_exec_main_checked (method, args, error);
4223 * mono_runtime_try_run_main:
4224 * @method: the method to start the application with (usually Main)
4225 * @argc: number of arguments from the command line
4226 * @argv: array of strings from the command line
4227 * @exc: set if Main throws an exception
4228 * @error: set if Main can't be executed
4230 * Execute a standard Main() method (argc/argv contains the executable
4231 * name). This method also sets the command line argument value needed
4232 * by System.Environment. On failure sets @error if Main can't be
4233 * executed or @exc if it threw and exception.
4238 mono_runtime_try_run_main (MonoMethod *method, int argc, char* argv[],
4242 MonoArray *args = prepare_run_main (method, argc, argv);
4243 return mono_runtime_try_exec_main (method, args, exc);
4248 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4250 static MonoMethod *serialize_method;
4256 if (!serialize_method) {
4257 MonoClass *klass = mono_class_get_remoting_services_class ();
4258 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
4261 if (!serialize_method) {
4266 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
4271 array = mono_runtime_try_invoke (serialize_method, NULL, params, exc, &error);
4272 if (*exc == NULL && !mono_error_ok (&error))
4273 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert serialize_object to MonoError */
4275 mono_error_cleanup (&error);
4284 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4286 MONO_REQ_GC_UNSAFE_MODE;
4288 static MonoMethod *deserialize_method;
4294 if (!deserialize_method) {
4295 MonoClass *klass = mono_class_get_remoting_services_class ();
4296 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
4298 if (!deserialize_method) {
4306 result = mono_runtime_try_invoke (deserialize_method, NULL, params, exc, &error);
4307 if (*exc == NULL && !mono_error_ok (&error))
4308 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert deserialize_object to MonoError */
4310 mono_error_cleanup (&error);
4318 #ifndef DISABLE_REMOTING
4320 make_transparent_proxy (MonoObject *obj, MonoError *error)
4322 MONO_REQ_GC_UNSAFE_MODE;
4324 static MonoMethod *get_proxy_method;
4326 MonoDomain *domain = mono_domain_get ();
4327 MonoRealProxy *real_proxy;
4328 MonoReflectionType *reflection_type;
4329 MonoTransparentProxy *transparent_proxy;
4333 if (!get_proxy_method)
4334 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
4336 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
4338 real_proxy = (MonoRealProxy*) mono_object_new_checked (domain, mono_defaults.real_proxy_class, error);
4339 return_val_if_nok (error, NULL);
4340 reflection_type = mono_type_get_object_checked (domain, &obj->vtable->klass->byval_arg, error);
4341 return_val_if_nok (error, NULL);
4343 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
4344 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
4346 MonoObject *exc = NULL;
4348 transparent_proxy = (MonoTransparentProxy*) mono_runtime_try_invoke (get_proxy_method, real_proxy, NULL, &exc, error);
4349 if (exc != NULL && is_ok (error))
4350 mono_error_set_exception_instance (error, (MonoException*)exc);
4352 return (MonoObject*) transparent_proxy;
4354 #endif /* DISABLE_REMOTING */
4357 * mono_object_xdomain_representation
4359 * @target_domain: a domain
4360 * @error: set on error.
4362 * Creates a representation of obj in the domain target_domain. This
4363 * is either a copy of obj arrived through via serialization and
4364 * deserialization or a proxy, depending on whether the object is
4365 * serializable or marshal by ref. obj must not be in target_domain.
4367 * If the object cannot be represented in target_domain, NULL is
4368 * returned and @error is set appropriately.
4371 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoError *error)
4373 MONO_REQ_GC_UNSAFE_MODE;
4376 MonoObject *deserialized = NULL;
4378 #ifndef DISABLE_REMOTING
4379 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
4380 deserialized = make_transparent_proxy (obj, error);
4385 gboolean failure = FALSE;
4386 MonoDomain *domain = mono_domain_get ();
4387 MonoObject *serialized;
4388 MonoObject *exc = NULL;
4390 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
4391 serialized = serialize_object (obj, &failure, &exc);
4392 mono_domain_set_internal_with_options (target_domain, FALSE);
4394 deserialized = deserialize_object (serialized, &failure, &exc);
4395 if (domain != target_domain)
4396 mono_domain_set_internal_with_options (domain, FALSE);
4398 mono_error_set_exception_instance (error, (MonoException*)exc);
4401 return deserialized;
4404 /* Used in call_unhandled_exception_delegate */
4406 create_unhandled_exception_eventargs (MonoObject *exc, MonoError *error)
4408 MONO_REQ_GC_UNSAFE_MODE;
4413 MonoMethod *method = NULL;
4414 MonoBoolean is_terminating = TRUE;
4417 klass = mono_class_get_unhandled_exception_event_args_class ();
4418 mono_class_init (klass);
4420 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4421 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
4425 args [1] = &is_terminating;
4427 obj = mono_object_new_checked (mono_domain_get (), klass, error);
4428 return_val_if_nok (error, NULL);
4430 mono_runtime_invoke_checked (method, obj, args, error);
4431 return_val_if_nok (error, NULL);
4436 /* Used in mono_unhandled_exception */
4438 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4439 MONO_REQ_GC_UNSAFE_MODE;
4442 MonoObject *e = NULL;
4444 MonoDomain *current_domain = mono_domain_get ();
4446 if (domain != current_domain)
4447 mono_domain_set_internal_with_options (domain, FALSE);
4449 g_assert (domain == mono_object_domain (domain->domain));
4451 if (mono_object_domain (exc) != domain) {
4453 exc = mono_object_xdomain_representation (exc, domain, &error);
4455 if (!is_ok (&error)) {
4456 MonoError inner_error;
4457 MonoException *serialization_exc = mono_error_convert_to_exception (&error);
4458 exc = mono_object_xdomain_representation ((MonoObject*)serialization_exc, domain, &inner_error);
4459 mono_error_assert_ok (&inner_error);
4461 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4462 "System.Runtime.Serialization", "SerializationException",
4463 "Could not serialize unhandled exception.");
4467 g_assert (mono_object_domain (exc) == domain);
4469 pa [0] = domain->domain;
4470 pa [1] = create_unhandled_exception_eventargs (exc, &error);
4471 mono_error_assert_ok (&error);
4472 mono_runtime_delegate_try_invoke (delegate, pa, &e, &error);
4473 if (!is_ok (&error)) {
4475 e = (MonoObject*)mono_error_convert_to_exception (&error);
4477 mono_error_cleanup (&error);
4480 if (domain != current_domain)
4481 mono_domain_set_internal_with_options (current_domain, FALSE);
4484 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4485 if (!mono_error_ok (&error)) {
4486 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4487 mono_error_cleanup (&error);
4489 g_warning ("exception inside UnhandledException handler: %s\n", msg);
4495 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4498 * mono_runtime_unhandled_exception_policy_set:
4499 * @policy: the new policy
4501 * This is a VM internal routine.
4503 * Sets the runtime policy for handling unhandled exceptions.
4506 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4507 runtime_unhandled_exception_policy = policy;
4511 * mono_runtime_unhandled_exception_policy_get:
4513 * This is a VM internal routine.
4515 * Gets the runtime policy for handling unhandled exceptions.
4517 MonoRuntimeUnhandledExceptionPolicy
4518 mono_runtime_unhandled_exception_policy_get (void) {
4519 return runtime_unhandled_exception_policy;
4523 * mono_unhandled_exception:
4524 * @exc: exception thrown
4526 * This is a VM internal routine.
4528 * We call this function when we detect an unhandled exception
4529 * in the default domain.
4531 * It invokes the * UnhandledException event in AppDomain or prints
4532 * a warning to the console
4535 mono_unhandled_exception (MonoObject *exc)
4537 MONO_REQ_GC_UNSAFE_MODE;
4540 MonoClassField *field;
4541 MonoDomain *current_domain, *root_domain;
4542 MonoObject *current_appdomain_delegate = NULL, *root_appdomain_delegate = NULL;
4544 if (mono_class_has_parent (exc->vtable->klass, mono_defaults.threadabortexception_class))
4547 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4550 current_domain = mono_domain_get ();
4551 root_domain = mono_get_root_domain ();
4553 root_appdomain_delegate = mono_field_get_value_object_checked (root_domain, field, (MonoObject*) root_domain->domain, &error);
4554 mono_error_assert_ok (&error);
4555 if (current_domain != root_domain) {
4556 current_appdomain_delegate = mono_field_get_value_object_checked (current_domain, field, (MonoObject*) current_domain->domain, &error);
4557 mono_error_assert_ok (&error);
4560 if (!current_appdomain_delegate && !root_appdomain_delegate) {
4561 mono_print_unhandled_exception (exc);
4563 /* unhandled exception callbacks must not be aborted */
4564 mono_threads_begin_abort_protected_block ();
4565 if (root_appdomain_delegate)
4566 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4567 if (current_appdomain_delegate)
4568 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4569 mono_threads_end_abort_protected_block ();
4572 /* set exitcode only if we will abort the process */
4573 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4574 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4576 mono_environment_exitcode_set (1);
4581 * mono_runtime_exec_managed_code:
4582 * @domain: Application domain
4583 * @main_func: function to invoke from the execution thread
4584 * @main_args: parameter to the main_func
4586 * Launch a new thread to execute a function
4588 * main_func is called back from the thread with main_args as the
4589 * parameter. The callback function is expected to start Main()
4590 * eventually. This function then waits for all managed threads to
4592 * It is not necesseray anymore to execute managed code in a subthread,
4593 * so this function should not be used anymore by default: just
4594 * execute the code and then call mono_thread_manage ().
4597 mono_runtime_exec_managed_code (MonoDomain *domain,
4598 MonoMainThreadFunc main_func,
4602 mono_thread_create_checked (domain, main_func, main_args, &error);
4603 mono_error_assert_ok (&error);
4605 mono_thread_manage ();
4609 prepare_thread_to_exec_main (MonoDomain *domain, MonoMethod *method)
4611 MonoInternalThread* thread = mono_thread_internal_current ();
4612 MonoCustomAttrInfo* cinfo;
4613 gboolean has_stathread_attribute;
4615 if (!domain->entry_assembly) {
4617 MonoAssembly *assembly;
4619 assembly = method->klass->image->assembly;
4620 domain->entry_assembly = assembly;
4621 /* Domains created from another domain already have application_base and configuration_file set */
4622 if (domain->setup->application_base == NULL) {
4623 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4626 if (domain->setup->configuration_file == NULL) {
4627 str = g_strconcat (assembly->image->name, ".config", NULL);
4628 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4630 mono_domain_set_options_from_config (domain);
4634 MonoError cattr_error;
4635 cinfo = mono_custom_attrs_from_method_checked (method, &cattr_error);
4636 mono_error_cleanup (&cattr_error); /* FIXME warn here? */
4638 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, mono_class_get_sta_thread_attribute_class ());
4640 mono_custom_attrs_free (cinfo);
4642 has_stathread_attribute = FALSE;
4644 if (has_stathread_attribute) {
4645 thread->apartment_state = ThreadApartmentState_STA;
4647 thread->apartment_state = ThreadApartmentState_MTA;
4649 mono_thread_init_apartment_state ();
4654 do_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4656 MONO_REQ_GC_UNSAFE_MODE;
4666 /* FIXME: check signature of method */
4667 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4669 res = mono_runtime_invoke_checked (method, NULL, pa, error);
4671 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4674 mono_environment_exitcode_set (rval);
4676 mono_runtime_invoke_checked (method, NULL, pa, error);
4688 do_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4690 MONO_REQ_GC_UNSAFE_MODE;
4700 /* FIXME: check signature of method */
4701 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4702 MonoError inner_error;
4704 res = mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4705 if (*exc == NULL && !mono_error_ok (&inner_error))
4706 *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4708 mono_error_cleanup (&inner_error);
4711 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4715 mono_environment_exitcode_set (rval);
4717 MonoError inner_error;
4718 mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4719 if (*exc == NULL && !mono_error_ok (&inner_error))
4720 *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4722 mono_error_cleanup (&inner_error);
4727 /* If the return type of Main is void, only
4728 * set the exitcode if an exception was thrown
4729 * (we don't want to blow away an
4730 * explicitly-set exit code)
4733 mono_environment_exitcode_set (rval);
4741 * Execute a standard Main() method (args doesn't contain the
4745 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4748 prepare_thread_to_exec_main (mono_object_domain (args), method);
4750 int rval = do_try_exec_main (method, args, exc);
4753 int rval = do_exec_main_checked (method, args, &error);
4754 mono_error_raise_exception (&error); /* OK to throw, external only with no better option */
4760 * Execute a standard Main() method (args doesn't contain the
4763 * On failure sets @error
4766 mono_runtime_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4769 prepare_thread_to_exec_main (mono_object_domain (args), method);
4770 return do_exec_main_checked (method, args, error);
4774 * Execute a standard Main() method (args doesn't contain the
4777 * On failure sets @error if Main couldn't be executed, or @exc if it threw an exception.
4780 mono_runtime_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4782 prepare_thread_to_exec_main (mono_object_domain (args), method);
4783 return do_try_exec_main (method, args, exc);
4788 /** invoke_array_extract_argument:
4789 * @params: array of arguments to the method.
4790 * @i: the index of the argument to extract.
4791 * @t: ith type from the method signature.
4792 * @has_byref_nullables: outarg - TRUE if method expects a byref nullable argument
4793 * @error: set on error.
4795 * Given an array of method arguments, return the ith one using the corresponding type
4796 * to perform necessary unboxing. If method expects a ref nullable argument, writes TRUE to @has_byref_nullables.
4798 * On failure sets @error and returns NULL.
4801 invoke_array_extract_argument (MonoArray *params, int i, MonoType *t, gboolean* has_byref_nullables, MonoError *error)
4803 MonoType *t_orig = t;
4804 gpointer result = NULL;
4810 case MONO_TYPE_BOOLEAN:
4813 case MONO_TYPE_CHAR:
4822 case MONO_TYPE_VALUETYPE:
4823 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (t_orig))) {
4824 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4825 result = mono_array_get (params, MonoObject*, i);
4827 *has_byref_nullables = TRUE;
4829 /* MS seems to create the objects if a null is passed in */
4830 if (!mono_array_get (params, MonoObject*, i)) {
4831 MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (t_orig), error);
4832 return_val_if_nok (error, NULL);
4833 mono_array_setref (params, i, o);
4838 * We can't pass the unboxed vtype byref to the callee, since
4839 * that would mean the callee would be able to modify boxed
4840 * primitive types. So we (and MS) make a copy of the boxed
4841 * object, pass that to the callee, and replace the original
4842 * boxed object in the arg array with the copy.
4844 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4845 MonoObject *copy = mono_value_box_checked (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig), error);
4846 return_val_if_nok (error, NULL);
4847 mono_array_setref (params, i, copy);
4850 result = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4853 case MONO_TYPE_STRING:
4854 case MONO_TYPE_OBJECT:
4855 case MONO_TYPE_CLASS:
4856 case MONO_TYPE_ARRAY:
4857 case MONO_TYPE_SZARRAY:
4859 result = mono_array_addr (params, MonoObject*, i);
4860 // FIXME: I need to check this code path
4862 result = mono_array_get (params, MonoObject*, i);
4864 case MONO_TYPE_GENERICINST:
4866 t = &t->data.generic_class->container_class->this_arg;
4868 t = &t->data.generic_class->container_class->byval_arg;
4870 case MONO_TYPE_PTR: {
4873 /* The argument should be an IntPtr */
4874 arg = mono_array_get (params, MonoObject*, i);
4878 g_assert (arg->vtable->klass == mono_defaults.int_class);
4879 result = ((MonoIntPtr*)arg)->m_value;
4884 g_error ("type 0x%x not handled in mono_runtime_invoke_array", t_orig->type);
4889 * mono_runtime_invoke_array:
4890 * @method: method to invoke
4891 * @obJ: object instance
4892 * @params: arguments to the method
4893 * @exc: exception information.
4895 * Invokes the method represented by @method on the object @obj.
4897 * obj is the 'this' pointer, it should be NULL for static
4898 * methods, a MonoObject* for object instances and a pointer to
4899 * the value type for value types.
4901 * The params array contains the arguments to the method with the
4902 * same convention: MonoObject* pointers for object instances and
4903 * pointers to the value type otherwise. The _invoke_array
4904 * variant takes a C# object[] as the params argument (MonoArray
4905 * *params): in this case the value types are boxed inside the
4906 * respective reference representation.
4908 * From unmanaged code you'll usually use the
4909 * mono_runtime_invoke_checked() variant.
4911 * Note that this function doesn't handle virtual methods for
4912 * you, it will exec the exact method you pass: we still need to
4913 * expose a function to lookup the derived class implementation
4914 * of a virtual method (there are examples of this in the code,
4917 * You can pass NULL as the exc argument if you don't want to
4918 * catch exceptions, otherwise, *exc will be set to the exception
4919 * thrown, if any. if an exception is thrown, you can't use the
4920 * MonoObject* result from the function.
4922 * If the method returns a value type, it is boxed in an object
4926 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4931 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, exc, &error);
4933 mono_error_cleanup (&error);
4936 if (!is_ok (&error))
4937 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
4941 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, NULL, &error);
4942 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
4948 * mono_runtime_invoke_array_checked:
4949 * @method: method to invoke
4950 * @obJ: object instance
4951 * @params: arguments to the method
4952 * @error: set on failure.
4954 * Invokes the method represented by @method on the object @obj.
4956 * obj is the 'this' pointer, it should be NULL for static
4957 * methods, a MonoObject* for object instances and a pointer to
4958 * the value type for value types.
4960 * The params array contains the arguments to the method with the
4961 * same convention: MonoObject* pointers for object instances and
4962 * pointers to the value type otherwise. The _invoke_array
4963 * variant takes a C# object[] as the params argument (MonoArray
4964 * *params): in this case the value types are boxed inside the
4965 * respective reference representation.
4967 * From unmanaged code you'll usually use the
4968 * mono_runtime_invoke_checked() variant.
4970 * Note that this function doesn't handle virtual methods for
4971 * you, it will exec the exact method you pass: we still need to
4972 * expose a function to lookup the derived class implementation
4973 * of a virtual method (there are examples of this in the code,
4976 * On failure or exception, @error will be set. In that case, you
4977 * can't use the MonoObject* result from the function.
4979 * If the method returns a value type, it is boxed in an object
4983 mono_runtime_invoke_array_checked (MonoMethod *method, void *obj, MonoArray *params,
4987 return mono_runtime_try_invoke_array (method, obj, params, NULL, error);
4991 * mono_runtime_try_invoke_array:
4992 * @method: method to invoke
4993 * @obJ: object instance
4994 * @params: arguments to the method
4995 * @exc: exception information.
4996 * @error: set on failure.
4998 * Invokes the method represented by @method on the object @obj.
5000 * obj is the 'this' pointer, it should be NULL for static
5001 * methods, a MonoObject* for object instances and a pointer to
5002 * the value type for value types.
5004 * The params array contains the arguments to the method with the
5005 * same convention: MonoObject* pointers for object instances and
5006 * pointers to the value type otherwise. The _invoke_array
5007 * variant takes a C# object[] as the params argument (MonoArray
5008 * *params): in this case the value types are boxed inside the
5009 * respective reference representation.
5011 * From unmanaged code you'll usually use the
5012 * mono_runtime_invoke_checked() variant.
5014 * Note that this function doesn't handle virtual methods for
5015 * you, it will exec the exact method you pass: we still need to
5016 * expose a function to lookup the derived class implementation
5017 * of a virtual method (there are examples of this in the code,
5020 * You can pass NULL as the exc argument if you don't want to catch
5021 * exceptions, otherwise, *exc will be set to the exception thrown, if
5022 * any. On other failures, @error will be set. If an exception is
5023 * thrown or there's an error, you can't use the MonoObject* result
5024 * from the function.
5026 * If the method returns a value type, it is boxed in an object
5030 mono_runtime_try_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
5031 MonoObject **exc, MonoError *error)
5033 MONO_REQ_GC_UNSAFE_MODE;
5037 MonoMethodSignature *sig = mono_method_signature (method);
5038 gpointer *pa = NULL;
5041 gboolean has_byref_nullables = FALSE;
5043 if (NULL != params) {
5044 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
5045 for (i = 0; i < mono_array_length (params); i++) {
5046 MonoType *t = sig->params [i];
5047 pa [i] = invoke_array_extract_argument (params, i, t, &has_byref_nullables, error);
5048 return_val_if_nok (error, NULL);
5052 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
5055 if (mono_class_is_nullable (method->klass)) {
5056 /* Need to create a boxed vtype instead */
5062 return mono_value_box_checked (mono_domain_get (), method->klass->cast_class, pa [0], error);
5067 obj = mono_object_new_checked (mono_domain_get (), method->klass, error);
5068 mono_error_assert_ok (error);
5069 g_assert (obj); /*maybe we should raise a TLE instead?*/
5070 #ifndef DISABLE_REMOTING
5071 if (mono_object_is_transparent_proxy (obj)) {
5072 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
5075 if (method->klass->valuetype)
5076 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
5079 } else if (method->klass->valuetype) {
5080 obj = mono_value_box_checked (mono_domain_get (), method->klass, obj, error);
5081 return_val_if_nok (error, NULL);
5085 mono_runtime_try_invoke (method, o, pa, exc, error);
5087 mono_runtime_invoke_checked (method, o, pa, error);
5090 return (MonoObject *)obj;
5092 if (mono_class_is_nullable (method->klass)) {
5093 MonoObject *nullable;
5095 /* Convert the unboxed vtype into a Nullable structure */
5096 nullable = mono_object_new_checked (mono_domain_get (), method->klass, error);
5097 return_val_if_nok (error, NULL);
5099 MonoObject *boxed = mono_value_box_checked (mono_domain_get (), method->klass->cast_class, obj, error);
5100 return_val_if_nok (error, NULL);
5101 mono_nullable_init ((guint8 *)mono_object_unbox (nullable), boxed, method->klass);
5102 obj = mono_object_unbox (nullable);
5105 /* obj must be already unboxed if needed */
5107 res = mono_runtime_try_invoke (method, obj, pa, exc, error);
5109 res = mono_runtime_invoke_checked (method, obj, pa, error);
5111 return_val_if_nok (error, NULL);
5113 if (sig->ret->type == MONO_TYPE_PTR) {
5114 MonoClass *pointer_class;
5115 static MonoMethod *box_method;
5117 MonoObject *box_exc;
5120 * The runtime-invoke wrapper returns a boxed IntPtr, need to
5121 * convert it to a Pointer object.
5123 pointer_class = mono_class_get_pointer_class ();
5125 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
5127 g_assert (res->vtable->klass == mono_defaults.int_class);
5128 box_args [0] = ((MonoIntPtr*)res)->m_value;
5129 box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, error);
5130 return_val_if_nok (error, NULL);
5132 res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, error);
5133 g_assert (box_exc == NULL);
5134 mono_error_assert_ok (error);
5137 if (has_byref_nullables) {
5139 * The runtime invoke wrapper already converted byref nullables back,
5140 * and stored them in pa, we just need to copy them back to the
5143 for (i = 0; i < mono_array_length (params); i++) {
5144 MonoType *t = sig->params [i];
5146 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
5147 mono_array_setref (params, i, pa [i]);
5157 * @klass: the class of the object that we want to create
5159 * Returns: a newly created object whose definition is
5160 * looked up using @klass. This will not invoke any constructors,
5161 * so the consumer of this routine has to invoke any constructors on
5162 * its own to initialize the object.
5164 * It returns NULL on failure.
5167 mono_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_cleanup (&error);
5180 ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
5182 MONO_REQ_GC_UNSAFE_MODE;
5186 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5188 mono_error_set_pending_exception (&error);
5193 * mono_object_new_checked:
5194 * @klass: the class of the object that we want to create
5195 * @error: set on error
5197 * Returns: a newly created object whose definition is
5198 * looked up using @klass. This will not invoke any constructors,
5199 * so the consumer of this routine has to invoke any constructors on
5200 * its own to initialize the object.
5202 * It returns NULL on failure and sets @error.
5205 mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
5207 MONO_REQ_GC_UNSAFE_MODE;
5211 vtable = mono_class_vtable (domain, klass);
5212 g_assert (vtable); /* FIXME don't swallow the error */
5214 MonoObject *o = mono_object_new_specific_checked (vtable, error);
5219 * mono_object_new_pinned:
5221 * Same as mono_object_new, but the returned object will be pinned.
5222 * For SGEN, these objects will only be freed at appdomain unload.
5225 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
5227 MONO_REQ_GC_UNSAFE_MODE;
5233 vtable = mono_class_vtable (domain, klass);
5234 g_assert (vtable); /* FIXME don't swallow the error */
5236 MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
5238 if (G_UNLIKELY (!o))
5239 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
5240 else if (G_UNLIKELY (vtable->klass->has_finalize))
5241 mono_object_register_finalizer (o);
5247 * mono_object_new_specific:
5248 * @vtable: the vtable of the object that we want to create
5250 * Returns: A newly created object with class and domain specified
5254 mono_object_new_specific (MonoVTable *vtable)
5257 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5258 mono_error_cleanup (&error);
5264 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
5266 MONO_REQ_GC_UNSAFE_MODE;
5272 /* check for is_com_object for COM Interop */
5273 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
5276 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
5279 MonoClass *klass = mono_class_get_activation_services_class ();
5282 mono_class_init (klass);
5284 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
5286 mono_error_set_not_supported (error, "Linked away.");
5289 vtable->domain->create_proxy_for_type_method = im;
5292 pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
5293 if (!mono_error_ok (error))
5296 o = mono_runtime_invoke_checked (im, NULL, pa, error);
5297 if (!mono_error_ok (error))
5304 return mono_object_new_alloc_specific_checked (vtable, error);
5308 ves_icall_object_new_specific (MonoVTable *vtable)
5311 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5312 mono_error_set_pending_exception (&error);
5318 * mono_object_new_alloc_specific:
5319 * @vtable: virtual table for the object.
5321 * This function allocates a new `MonoObject` with the type derived
5322 * from the @vtable information. If the class of this object has a
5323 * finalizer, then the object will be tracked for finalization.
5325 * This method might raise an exception on errors. Use the
5326 * `mono_object_new_fast_checked` method if you want to manually raise
5329 * Returns: the allocated object.
5332 mono_object_new_alloc_specific (MonoVTable *vtable)
5335 MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
5336 mono_error_cleanup (&error);
5342 * mono_object_new_alloc_specific_checked:
5343 * @vtable: virtual table for the object.
5344 * @error: holds the error return value.
5346 * This function allocates a new `MonoObject` with the type derived
5347 * from the @vtable information. If the class of this object has a
5348 * finalizer, then the object will be tracked for finalization.
5350 * If there is not enough memory, the @error parameter will be set
5351 * and will contain a user-visible message with the amount of bytes
5352 * that were requested.
5354 * Returns: the allocated object, or NULL if there is not enough memory
5358 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
5360 MONO_REQ_GC_UNSAFE_MODE;
5366 o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5368 if (G_UNLIKELY (!o))
5369 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5370 else if (G_UNLIKELY (vtable->klass->has_finalize))
5371 mono_object_register_finalizer (o);
5377 * mono_object_new_fast:
5378 * @vtable: virtual table for the object.
5380 * This function allocates a new `MonoObject` with the type derived
5381 * from the @vtable information. The returned object is not tracked
5382 * for finalization. If your object implements a finalizer, you should
5383 * use `mono_object_new_alloc_specific` instead.
5385 * This method might raise an exception on errors. Use the
5386 * `mono_object_new_fast_checked` method if you want to manually raise
5389 * Returns: the allocated object.
5392 mono_object_new_fast (MonoVTable *vtable)
5395 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5396 mono_error_cleanup (&error);
5402 * mono_object_new_fast_checked:
5403 * @vtable: virtual table for the object.
5404 * @error: holds the error return value.
5406 * This function allocates a new `MonoObject` with the type derived
5407 * from the @vtable information. The returned object is not tracked
5408 * for finalization. If your object implements a finalizer, you should
5409 * use `mono_object_new_alloc_specific_checked` instead.
5411 * If there is not enough memory, the @error parameter will be set
5412 * and will contain a user-visible message with the amount of bytes
5413 * that were requested.
5415 * Returns: the allocated object, or NULL if there is not enough memory
5419 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
5421 MONO_REQ_GC_UNSAFE_MODE;
5427 o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5429 if (G_UNLIKELY (!o))
5430 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5436 ves_icall_object_new_fast (MonoVTable *vtable)
5439 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5440 mono_error_set_pending_exception (&error);
5446 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
5448 MONO_REQ_GC_UNSAFE_MODE;
5454 o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
5456 if (G_UNLIKELY (!o))
5457 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5458 else if (G_UNLIKELY (vtable->klass->has_finalize))
5459 mono_object_register_finalizer (o);
5465 * mono_class_get_allocation_ftn:
5467 * @for_box: the object will be used for boxing
5468 * @pass_size_in_words:
5470 * Return the allocation function appropriate for the given class.
5474 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
5476 MONO_REQ_GC_NEUTRAL_MODE;
5478 *pass_size_in_words = FALSE;
5480 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass))
5481 return ves_icall_object_new_specific;
5483 if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
5485 return ves_icall_object_new_fast;
5488 * FIXME: This is actually slower than ves_icall_object_new_fast, because
5489 * of the overhead of parameter passing.
5492 *pass_size_in_words = TRUE;
5493 #ifdef GC_REDIRECT_TO_LOCAL
5494 return GC_local_gcj_fast_malloc;
5496 return GC_gcj_fast_malloc;
5501 return ves_icall_object_new_specific;
5505 * mono_object_new_from_token:
5506 * @image: Context where the type_token is hosted
5507 * @token: a token of the type that we want to create
5509 * Returns: A newly created object whose definition is
5510 * looked up using @token in the @image image
5513 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
5515 MONO_REQ_GC_UNSAFE_MODE;
5521 klass = mono_class_get_checked (image, token, &error);
5522 mono_error_assert_ok (&error);
5524 result = mono_object_new_checked (domain, klass, &error);
5526 mono_error_cleanup (&error);
5533 * mono_object_clone:
5534 * @obj: the object to clone
5536 * Returns: A newly created object who is a shallow copy of @obj
5539 mono_object_clone (MonoObject *obj)
5542 MonoObject *o = mono_object_clone_checked (obj, &error);
5543 mono_error_cleanup (&error);
5549 mono_object_clone_checked (MonoObject *obj, MonoError *error)
5551 MONO_REQ_GC_UNSAFE_MODE;
5558 size = obj->vtable->klass->instance_size;
5560 if (obj->vtable->klass->rank)
5561 return (MonoObject*)mono_array_clone_checked ((MonoArray*)obj, error);
5563 o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
5565 if (G_UNLIKELY (!o)) {
5566 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5570 /* If the object doesn't contain references this will do a simple memmove. */
5571 mono_gc_wbarrier_object_copy (o, obj);
5573 if (obj->vtable->klass->has_finalize)
5574 mono_object_register_finalizer (o);
5579 * mono_array_full_copy:
5580 * @src: source array to copy
5581 * @dest: destination array
5583 * Copies the content of one array to another with exactly the same type and size.
5586 mono_array_full_copy (MonoArray *src, MonoArray *dest)
5588 MONO_REQ_GC_UNSAFE_MODE;
5591 MonoClass *klass = src->obj.vtable->klass;
5593 g_assert (klass == dest->obj.vtable->klass);
5595 size = mono_array_length (src);
5596 g_assert (size == mono_array_length (dest));
5597 size *= mono_array_element_size (klass);
5599 array_full_copy_unchecked_size (src, dest, klass, size);
5603 array_full_copy_unchecked_size (MonoArray *src, MonoArray *dest, MonoClass *klass, uintptr_t size)
5606 if (klass->element_class->valuetype) {
5607 if (klass->element_class->has_references)
5608 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
5610 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5612 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
5615 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5620 * mono_array_clone_in_domain:
5621 * @domain: the domain in which the array will be cloned into
5622 * @array: the array to clone
5623 * @error: set on error
5625 * This routine returns a copy of the array that is hosted on the
5626 * specified MonoDomain. On failure returns NULL and sets @error.
5629 mono_array_clone_in_domain (MonoDomain *domain, MonoArrayHandle array_handle, MonoError *error)
5631 MONO_REQ_GC_UNSAFE_MODE;
5633 MonoArrayHandle result = MONO_HANDLE_NEW (MonoArray, NULL);
5635 MonoClass *klass = mono_handle_class (array_handle);
5639 /* Pin source array here - if bounds is non-NULL, it's a pointer into the object data */
5640 uint32_t src_handle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, array_handle), TRUE);
5642 MonoArrayBounds *array_bounds = MONO_HANDLE_GETVAL (array_handle, bounds);
5644 if (array_bounds == NULL) {
5645 size = mono_array_handle_length (array_handle);
5646 o = mono_array_new_full_handle (domain, klass, &size, NULL, error);
5649 size *= mono_array_element_size (klass);
5651 uintptr_t *sizes = (uintptr_t *)alloca (klass->rank * sizeof (uintptr_t));
5652 intptr_t *lower_bounds = (intptr_t *)alloca (klass->rank * sizeof (intptr_t));
5653 size = mono_array_element_size (klass);
5654 for (int i = 0; i < klass->rank; ++i) {
5655 sizes [i] = array_bounds [i].length;
5656 size *= array_bounds [i].length;
5657 lower_bounds [i] = array_bounds [i].lower_bound;
5659 o = mono_array_new_full_handle (domain, klass, sizes, lower_bounds, error);
5664 uint32_t dst_handle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, o), TRUE);
5665 array_full_copy_unchecked_size (MONO_HANDLE_RAW (array_handle), MONO_HANDLE_RAW (o), klass, size);
5666 mono_gchandle_free (dst_handle);
5668 MONO_HANDLE_ASSIGN (result, o);
5671 mono_gchandle_free (src_handle);
5677 * @array: the array to clone
5679 * Returns: A newly created array who is a shallow copy of @array
5682 mono_array_clone (MonoArray *array)
5684 MONO_REQ_GC_UNSAFE_MODE;
5687 MonoArray *result = mono_array_clone_checked (array, &error);
5688 mono_error_cleanup (&error);
5693 * mono_array_clone_checked:
5694 * @array: the array to clone
5695 * @error: set on error
5697 * Returns: A newly created array who is a shallow copy of @array. On
5698 * failure returns NULL and sets @error.
5701 mono_array_clone_checked (MonoArray *array_raw, MonoError *error)
5703 MONO_REQ_GC_UNSAFE_MODE;
5704 HANDLE_FUNCTION_ENTER ();
5705 /* FIXME: callers of mono_array_clone_checked should use handles */
5707 MONO_HANDLE_DCL (MonoArray, array);
5708 MonoArrayHandle result = mono_array_clone_in_domain (MONO_HANDLE_DOMAIN (array), array, error);
5709 HANDLE_FUNCTION_RETURN_OBJ (result);
5712 /* helper macros to check for overflow when calculating the size of arrays */
5713 #ifdef MONO_BIG_ARRAYS
5714 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
5715 #define MYGUINT_MAX MYGUINT64_MAX
5716 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5717 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
5718 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5719 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
5720 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
5722 #define MYGUINT32_MAX 4294967295U
5723 #define MYGUINT_MAX MYGUINT32_MAX
5724 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5725 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
5726 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5727 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
5728 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
5732 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
5734 MONO_REQ_GC_NEUTRAL_MODE;
5738 byte_len = mono_array_element_size (klass);
5739 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
5742 if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
5744 byte_len += MONO_SIZEOF_MONO_ARRAY;
5752 * mono_array_new_full:
5753 * @domain: domain where the object is created
5754 * @array_class: array class
5755 * @lengths: lengths for each dimension in the array
5756 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
5758 * This routine creates a new array objects with the given dimensions,
5759 * lower bounds and type.
5762 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
5765 MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
5766 mono_error_cleanup (&error);
5772 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
5774 MONO_REQ_GC_UNSAFE_MODE;
5776 uintptr_t byte_len = 0, len, bounds_size;
5779 MonoArrayBounds *bounds;
5785 if (!array_class->inited)
5786 mono_class_init (array_class);
5790 /* A single dimensional array with a 0 lower bound is the same as an szarray */
5791 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
5793 if (len > MONO_ARRAY_MAX_INDEX) {
5794 mono_error_set_generic_error (error, "System", "OverflowException", "");
5799 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
5801 for (i = 0; i < array_class->rank; ++i) {
5802 if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
5803 mono_error_set_generic_error (error, "System", "OverflowException", "");
5806 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5807 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5814 if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5815 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5821 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5822 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5825 byte_len = (byte_len + 3) & ~3;
5826 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5827 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5830 byte_len += bounds_size;
5833 * Following three lines almost taken from mono_object_new ():
5834 * they need to be kept in sync.
5836 vtable = mono_class_vtable_full (domain, array_class, error);
5837 return_val_if_nok (error, NULL);
5840 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5842 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5844 if (G_UNLIKELY (!o)) {
5845 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5849 array = (MonoArray*)o;
5851 bounds = array->bounds;
5854 for (i = 0; i < array_class->rank; ++i) {
5855 bounds [i].length = lengths [i];
5857 bounds [i].lower_bound = lower_bounds [i];
5866 * @domain: domain where the object is created
5867 * @eclass: element class
5868 * @n: number of array elements
5870 * This routine creates a new szarray with @n elements of type @eclass.
5873 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5875 MONO_REQ_GC_UNSAFE_MODE;
5878 MonoArray *result = mono_array_new_checked (domain, eclass, n, &error);
5879 mono_error_cleanup (&error);
5884 * mono_array_new_checked:
5885 * @domain: domain where the object is created
5886 * @eclass: element class
5887 * @n: number of array elements
5888 * @error: set on error
5890 * This routine creates a new szarray with @n elements of type @eclass.
5891 * On failure returns NULL and sets @error.
5894 mono_array_new_checked (MonoDomain *domain, MonoClass *eclass, uintptr_t n, MonoError *error)
5900 ac = mono_array_class_get (eclass, 1);
5903 MonoVTable *vtable = mono_class_vtable_full (domain, ac, error);
5904 return_val_if_nok (error, NULL);
5906 return mono_array_new_specific_checked (vtable, n, error);
5910 ves_icall_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5913 MonoArray *arr = mono_array_new_checked (domain, eclass, n, &error);
5914 mono_error_set_pending_exception (&error);
5920 * mono_array_new_specific:
5921 * @vtable: a vtable in the appropriate domain for an initialized class
5922 * @n: number of array elements
5924 * This routine is a fast alternative to mono_array_new() for code which
5925 * can be sure about the domain it operates in.
5928 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5931 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5932 mono_error_cleanup (&error);
5938 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
5940 MONO_REQ_GC_UNSAFE_MODE;
5947 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
5948 mono_error_set_generic_error (error, "System", "OverflowException", "");
5952 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
5953 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5956 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
5958 if (G_UNLIKELY (!o)) {
5959 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5963 return (MonoArray*)o;
5967 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
5970 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5971 mono_error_set_pending_exception (&error);
5977 * mono_string_empty_wrapper:
5979 * Returns: The same empty string instance as the managed string.Empty
5982 mono_string_empty_wrapper (void)
5984 MonoDomain *domain = mono_domain_get ();
5985 return mono_string_empty (domain);
5989 * mono_string_empty:
5991 * Returns: The same empty string instance as the managed string.Empty
5994 mono_string_empty (MonoDomain *domain)
5997 g_assert (domain->empty_string);
5998 return domain->empty_string;
6002 * mono_string_new_utf16:
6003 * @text: a pointer to an utf16 string
6004 * @len: the length of the string
6006 * Returns: A newly created string object which contains @text.
6009 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
6011 MONO_REQ_GC_UNSAFE_MODE;
6014 MonoString *res = NULL;
6015 res = mono_string_new_utf16_checked (domain, text, len, &error);
6016 mono_error_cleanup (&error);
6022 * mono_string_new_utf16_checked:
6023 * @text: a pointer to an utf16 string
6024 * @len: the length of the string
6025 * @error: written on error.
6027 * Returns: A newly created string object which contains @text.
6028 * On error, returns NULL and sets @error.
6031 mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
6033 MONO_REQ_GC_UNSAFE_MODE;
6039 s = mono_string_new_size_checked (domain, len, error);
6041 memcpy (mono_string_chars (s), text, len * 2);
6047 * mono_string_new_utf16_handle:
6048 * @text: a pointer to an utf16 string
6049 * @len: the length of the string
6050 * @error: written on error.
6052 * Returns: A newly created string object which contains @text.
6053 * On error, returns NULL and sets @error.
6056 mono_string_new_utf16_handle (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
6058 return MONO_HANDLE_NEW (MonoString, mono_string_new_utf16_checked (domain, text, len, error));
6062 * mono_string_new_utf32:
6063 * @text: a pointer to an utf32 string
6064 * @len: the length of the string
6065 * @error: set on failure.
6067 * Returns: A newly created string object which contains @text. On failure returns NULL and sets @error.
6070 mono_string_new_utf32_checked (MonoDomain *domain, const mono_unichar4 *text, gint32 len, MonoError *error)
6072 MONO_REQ_GC_UNSAFE_MODE;
6075 mono_unichar2 *utf16_output = NULL;
6076 gint32 utf16_len = 0;
6077 GError *gerror = NULL;
6078 glong items_written;
6081 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
6084 g_error_free (gerror);
6086 while (utf16_output [utf16_len]) utf16_len++;
6088 s = mono_string_new_size_checked (domain, utf16_len, error);
6089 return_val_if_nok (error, NULL);
6091 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
6093 g_free (utf16_output);
6099 * mono_string_new_utf32:
6100 * @text: a pointer to an utf32 string
6101 * @len: the length of the string
6103 * Returns: A newly created string object which contains @text.
6106 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
6109 MonoString *result = mono_string_new_utf32_checked (domain, text, len, &error);
6110 mono_error_cleanup (&error);
6115 * mono_string_new_size:
6116 * @text: a pointer to an utf16 string
6117 * @len: the length of the string
6119 * Returns: A newly created string object of @len
6122 mono_string_new_size (MonoDomain *domain, gint32 len)
6125 MonoString *str = mono_string_new_size_checked (domain, len, &error);
6126 mono_error_cleanup (&error);
6132 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
6134 MONO_REQ_GC_UNSAFE_MODE;
6142 /* check for overflow */
6143 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
6144 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
6148 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
6149 g_assert (size > 0);
6151 vtable = mono_class_vtable (domain, mono_defaults.string_class);
6154 s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
6156 if (G_UNLIKELY (!s)) {
6157 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", size);
6165 * mono_string_new_len:
6166 * @text: a pointer to an utf8 string
6167 * @length: number of bytes in @text to consider
6169 * Returns: A newly created string object which contains @text.
6172 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
6174 MONO_REQ_GC_UNSAFE_MODE;
6177 MonoString *result = mono_string_new_len_checked (domain, text, length, &error);
6178 mono_error_cleanup (&error);
6183 * mono_string_new_len_checked:
6184 * @text: a pointer to an utf8 string
6185 * @length: number of bytes in @text to consider
6186 * @error: set on error
6188 * Returns: A newly created string object which contains @text. On
6189 * failure returns NULL and sets @error.
6192 mono_string_new_len_checked (MonoDomain *domain, const char *text, guint length, MonoError *error)
6194 MONO_REQ_GC_UNSAFE_MODE;
6198 GError *eg_error = NULL;
6199 MonoString *o = NULL;
6201 glong items_written;
6203 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
6206 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6208 g_error_free (eg_error);
6217 * @text: a pointer to an utf8 string
6219 * Returns: A newly created string object which contains @text.
6221 * This function asserts if it cannot allocate a new string.
6223 * @deprecated Use mono_string_new_checked in new code.
6226 mono_string_new (MonoDomain *domain, const char *text)
6229 MonoString *res = NULL;
6230 res = mono_string_new_checked (domain, text, &error);
6231 mono_error_assert_ok (&error);
6236 * mono_string_new_checked:
6237 * @text: a pointer to an utf8 string
6238 * @merror: set on error
6240 * Returns: A newly created string object which contains @text.
6241 * On error returns NULL and sets @merror.
6244 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
6246 MONO_REQ_GC_UNSAFE_MODE;
6248 GError *eg_error = NULL;
6249 MonoString *o = NULL;
6251 glong items_written;
6258 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &eg_error);
6261 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6263 g_error_free (eg_error);
6267 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
6272 MonoString *o = NULL;
6274 if (!g_utf8_validate (text, -1, &end)) {
6275 mono_error_set_argument (error, "text", "Not a valid utf8 string");
6279 len = g_utf8_strlen (text, -1);
6280 o = mono_string_new_size_checked (domain, len, error);
6283 str = mono_string_chars (o);
6285 while (text < end) {
6286 *str++ = g_utf8_get_char (text);
6287 text = g_utf8_next_char (text);
6296 * mono_string_new_wrapper:
6297 * @text: pointer to utf8 characters.
6299 * Helper function to create a string object from @text in the current domain.
6302 mono_string_new_wrapper (const char *text)
6304 MONO_REQ_GC_UNSAFE_MODE;
6306 MonoDomain *domain = mono_domain_get ();
6309 return mono_string_new (domain, text);
6316 * @class: the class of the value
6317 * @value: a pointer to the unboxed data
6319 * Returns: A newly created object which contains @value.
6322 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
6325 MonoObject *result = mono_value_box_checked (domain, klass, value, &error);
6326 mono_error_cleanup (&error);
6331 * mono_value_box_checked:
6332 * @domain: the domain of the new object
6333 * @class: the class of the value
6334 * @value: a pointer to the unboxed data
6335 * @error: set on error
6337 * Returns: A newly created object which contains @value. On failure
6338 * returns NULL and sets @error.
6341 mono_value_box_checked (MonoDomain *domain, MonoClass *klass, gpointer value, MonoError *error)
6343 MONO_REQ_GC_UNSAFE_MODE;
6350 g_assert (klass->valuetype);
6351 if (mono_class_is_nullable (klass))
6352 return mono_nullable_box ((guint8 *)value, klass, error);
6354 vtable = mono_class_vtable (domain, klass);
6357 size = mono_class_instance_size (klass);
6358 res = mono_object_new_alloc_specific_checked (vtable, error);
6359 return_val_if_nok (error, NULL);
6361 size = size - sizeof (MonoObject);
6364 g_assert (size == mono_class_value_size (klass, NULL));
6365 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
6367 #if NO_UNALIGNED_ACCESS
6368 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6372 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
6375 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
6378 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
6381 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
6384 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6388 if (klass->has_finalize) {
6389 mono_object_register_finalizer (res);
6390 return_val_if_nok (error, NULL);
6397 * @dest: destination pointer
6398 * @src: source pointer
6399 * @klass: a valuetype class
6401 * Copy a valuetype from @src to @dest. This function must be used
6402 * when @klass contains references fields.
6405 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
6407 MONO_REQ_GC_UNSAFE_MODE;
6409 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
6413 * mono_value_copy_array:
6414 * @dest: destination array
6415 * @dest_idx: index in the @dest array
6416 * @src: source pointer
6417 * @count: number of items
6419 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
6420 * This function must be used when @klass contains references fields.
6421 * Overlap is handled.
6424 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
6426 MONO_REQ_GC_UNSAFE_MODE;
6428 int size = mono_array_element_size (dest->obj.vtable->klass);
6429 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
6430 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
6431 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
6435 * mono_object_get_domain:
6436 * @obj: object to query
6438 * Returns: the MonoDomain where the object is hosted
6441 mono_object_get_domain (MonoObject *obj)
6443 MONO_REQ_GC_UNSAFE_MODE;
6445 return mono_object_domain (obj);
6449 * mono_object_get_class:
6450 * @obj: object to query
6452 * Use this function to obtain the `MonoClass*` for a given `MonoObject`.
6454 * Returns: the MonoClass of the object.
6457 mono_object_get_class (MonoObject *obj)
6459 MONO_REQ_GC_UNSAFE_MODE;
6461 return mono_object_class (obj);
6464 * mono_object_get_size:
6465 * @o: object to query
6467 * Returns: the size, in bytes, of @o
6470 mono_object_get_size (MonoObject* o)
6472 MONO_REQ_GC_UNSAFE_MODE;
6474 MonoClass* klass = mono_object_class (o);
6475 if (klass == mono_defaults.string_class) {
6476 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
6477 } else if (o->vtable->rank) {
6478 MonoArray *array = (MonoArray*)o;
6479 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
6480 if (array->bounds) {
6483 size += sizeof (MonoArrayBounds) * o->vtable->rank;
6487 return mono_class_instance_size (klass);
6492 * mono_object_unbox:
6493 * @obj: object to unbox
6495 * Returns: a pointer to the start of the valuetype boxed in this
6498 * This method will assert if the object passed is not a valuetype.
6501 mono_object_unbox (MonoObject *obj)
6503 MONO_REQ_GC_UNSAFE_MODE;
6505 /* add assert for valuetypes? */
6506 g_assert (obj->vtable->klass->valuetype);
6507 return ((char*)obj) + sizeof (MonoObject);
6511 * mono_object_isinst:
6513 * @klass: a pointer to a class
6515 * Returns: @obj if @obj is derived from @klass or NULL otherwise.
6518 mono_object_isinst (MonoObject *obj_raw, MonoClass *klass)
6520 MONO_REQ_GC_UNSAFE_MODE;
6522 HANDLE_FUNCTION_ENTER ();
6523 MONO_HANDLE_DCL (MonoObject, obj);
6525 MonoObjectHandle result = mono_object_handle_isinst (obj, klass, &error);
6526 mono_error_cleanup (&error);
6527 HANDLE_FUNCTION_RETURN_OBJ (result);
6532 * mono_object_isinst_checked:
6534 * @klass: a pointer to a class
6535 * @error: set on error
6537 * Returns: @obj if @obj is derived from @klass or NULL if it isn't.
6538 * On failure returns NULL and sets @error.
6541 mono_object_isinst_checked (MonoObject *obj_raw, MonoClass *klass, MonoError *error)
6543 MONO_REQ_GC_UNSAFE_MODE;
6545 HANDLE_FUNCTION_ENTER ();
6547 MONO_HANDLE_DCL (MonoObject, obj);
6548 MonoObjectHandle result = mono_object_handle_isinst (obj, klass, error);
6549 HANDLE_FUNCTION_RETURN_OBJ (result);
6553 * mono_object_handle_isinst:
6555 * @klass: a pointer to a class
6556 * @error: set on error
6558 * Returns: @obj if @obj is derived from @klass or NULL if it isn't.
6559 * On failure returns NULL and sets @error.
6562 mono_object_handle_isinst (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
6567 mono_class_init (klass);
6569 if (mono_class_is_marshalbyref (klass) || mono_class_is_interface (klass)) {
6570 return mono_object_handle_isinst_mbyref (obj, klass, error);
6573 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6575 if (!MONO_HANDLE_IS_NULL (obj) && mono_class_is_assignable_from (klass, mono_handle_class (obj)))
6576 MONO_HANDLE_ASSIGN (result, obj);
6581 mono_object_isinst_mbyref (MonoObject *obj_raw, MonoClass *klass)
6583 MONO_REQ_GC_UNSAFE_MODE;
6585 HANDLE_FUNCTION_ENTER ();
6587 MONO_HANDLE_DCL (MonoObject, obj);
6588 MonoObjectHandle result = mono_object_handle_isinst_mbyref (obj, klass, &error);
6589 mono_error_cleanup (&error); /* FIXME better API that doesn't swallow the error */
6590 HANDLE_FUNCTION_RETURN_OBJ (result);
6594 mono_object_handle_isinst_mbyref (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
6598 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6600 if (MONO_HANDLE_IS_NULL (obj))
6603 MonoVTable *vt = MONO_HANDLE_GETVAL (obj, vtable);
6605 if (mono_class_is_interface (klass)) {
6606 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
6607 MONO_HANDLE_ASSIGN (result, obj);
6611 /* casting an array one of the invariant interfaces that must act as such */
6612 if (klass->is_array_special_interface) {
6613 if (mono_class_is_assignable_from (klass, vt->klass)) {
6614 MONO_HANDLE_ASSIGN (result, obj);
6619 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
6620 else if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, mono_handle_class (obj))) {
6621 MONO_HANDLE_ASSIGN (result, obj);
6625 MonoClass *oklass = vt->klass;
6626 if (mono_class_is_transparent_proxy (oklass)){
6627 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), remote_class);
6628 oklass = remote_class->proxy_class;
6631 mono_class_setup_supertypes (klass);
6632 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass)) {
6633 MONO_HANDLE_ASSIGN (result, obj);
6637 #ifndef DISABLE_REMOTING
6638 if (mono_class_is_transparent_proxy (vt->klass))
6640 MonoBoolean custom_type_info = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), custom_type_info);
6641 if (!custom_type_info)
6643 MonoDomain *domain = mono_domain_get ();
6644 MonoObjectHandle rp = MONO_HANDLE_NEW (MonoObject, NULL);
6645 MONO_HANDLE_GET (rp, MONO_HANDLE_CAST (MonoTransparentProxy, obj), rp);
6646 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
6647 MonoMethod *im = NULL;
6650 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
6652 mono_error_set_not_supported (error, "Linked away.");
6655 im = mono_object_handle_get_virtual_method (rp, im, error);
6660 MonoReflectionTypeHandle reftype = mono_type_get_object_handle (domain, &klass->byval_arg, error);
6664 pa [0] = MONO_HANDLE_RAW (reftype);
6665 pa [1] = MONO_HANDLE_RAW (obj);
6666 MonoObject *res = mono_runtime_invoke_checked (im, rp, pa, error);
6670 if (*(MonoBoolean *) mono_object_unbox(res)) {
6671 /* Update the vtable of the remote type, so it can safely cast to this new type */
6672 mono_upgrade_remote_class (domain, obj, klass, error);
6675 MONO_HANDLE_ASSIGN (result, obj);
6678 #endif /* DISABLE_REMOTING */
6684 * mono_object_castclass_mbyref:
6686 * @klass: a pointer to a class
6688 * Returns: @obj if @obj is derived from @klass, returns NULL otherwise.
6691 mono_object_castclass_mbyref (MonoObject *obj_raw, MonoClass *klass)
6693 MONO_REQ_GC_UNSAFE_MODE;
6694 HANDLE_FUNCTION_ENTER ();
6696 MONO_HANDLE_DCL (MonoObject, obj);
6697 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6698 if (MONO_HANDLE_IS_NULL (obj))
6700 MONO_HANDLE_ASSIGN (result, mono_object_handle_isinst_mbyref (obj, klass, &error));
6701 mono_error_cleanup (&error);
6703 HANDLE_FUNCTION_RETURN_OBJ (result);
6707 MonoDomain *orig_domain;
6713 str_lookup (MonoDomain *domain, gpointer user_data)
6715 MONO_REQ_GC_UNSAFE_MODE;
6717 LDStrInfo *info = (LDStrInfo *)user_data;
6718 if (info->res || domain == info->orig_domain)
6720 info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
6724 mono_string_get_pinned (MonoString *str, MonoError *error)
6726 MONO_REQ_GC_UNSAFE_MODE;
6730 /* We only need to make a pinned version of a string if this is a moving GC */
6731 if (!mono_gc_is_moving ())
6735 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
6736 news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
6738 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
6739 news->length = mono_string_length (str);
6741 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6747 mono_string_is_interned_lookup (MonoString *str, int insert, MonoError *error)
6749 MONO_REQ_GC_UNSAFE_MODE;
6751 MonoGHashTable *ldstr_table;
6752 MonoString *s, *res;
6757 domain = ((MonoObject *)str)->vtable->domain;
6758 ldstr_table = domain->ldstr_table;
6760 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6766 /* Allocate outside the lock */
6768 s = mono_string_get_pinned (str, error);
6769 return_val_if_nok (error, NULL);
6772 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6777 mono_g_hash_table_insert (ldstr_table, s, s);
6782 LDStrInfo ldstr_info;
6783 ldstr_info.orig_domain = domain;
6784 ldstr_info.ins = str;
6785 ldstr_info.res = NULL;
6787 mono_domain_foreach (str_lookup, &ldstr_info);
6788 if (ldstr_info.res) {
6790 * the string was already interned in some other domain:
6791 * intern it in the current one as well.
6793 mono_g_hash_table_insert (ldstr_table, str, str);
6803 * mono_string_is_interned:
6804 * @o: String to probe
6806 * Returns whether the string has been interned.
6809 mono_string_is_interned (MonoString *o)
6812 MonoString *result = mono_string_is_interned_lookup (o, FALSE, &error);
6813 /* This function does not fail. */
6814 mono_error_assert_ok (&error);
6819 * mono_string_intern:
6820 * @o: String to intern
6822 * Interns the string passed.
6823 * Returns: The interned string.
6826 mono_string_intern (MonoString *str)
6829 MonoString *result = mono_string_intern_checked (str, &error);
6830 mono_error_assert_ok (&error);
6835 * mono_string_intern_checked:
6836 * @o: String to intern
6837 * @error: set on error.
6839 * Interns the string passed.
6840 * Returns: The interned string. On failure returns NULL and sets @error
6843 mono_string_intern_checked (MonoString *str, MonoError *error)
6845 MONO_REQ_GC_UNSAFE_MODE;
6849 return mono_string_is_interned_lookup (str, TRUE, error);
6854 * @domain: the domain where the string will be used.
6855 * @image: a metadata context
6856 * @idx: index into the user string table.
6858 * Implementation for the ldstr opcode.
6859 * Returns: a loaded string from the @image/@idx combination.
6862 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
6865 MonoString *result = mono_ldstr_checked (domain, image, idx, &error);
6866 mono_error_cleanup (&error);
6871 * mono_ldstr_checked:
6872 * @domain: the domain where the string will be used.
6873 * @image: a metadata context
6874 * @idx: index into the user string table.
6875 * @error: set on error.
6877 * Implementation for the ldstr opcode.
6878 * Returns: a loaded string from the @image/@idx combination.
6879 * On failure returns NULL and sets @error.
6882 mono_ldstr_checked (MonoDomain *domain, MonoImage *image, guint32 idx, MonoError *error)
6884 MONO_REQ_GC_UNSAFE_MODE;
6887 if (image->dynamic) {
6888 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL, error);
6891 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6892 return NULL; /*FIXME we should probably be raising an exception here*/
6893 MonoString *str = mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx), error);
6899 * mono_ldstr_metadata_sig
6900 * @domain: the domain for the string
6901 * @sig: the signature of a metadata string
6902 * @error: set on error
6904 * Returns: a MonoString for a string stored in the metadata. On
6905 * failure returns NULL and sets @error.
6908 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error)
6910 MONO_REQ_GC_UNSAFE_MODE;
6913 const char *str = sig;
6914 MonoString *o, *interned;
6917 len2 = mono_metadata_decode_blob_size (str, &str);
6920 o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, error);
6921 return_val_if_nok (error, NULL);
6922 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
6925 guint16 *p2 = (guint16*)mono_string_chars (o);
6926 for (i = 0; i < len2; ++i) {
6927 *p2 = GUINT16_FROM_LE (*p2);
6933 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6936 return interned; /* o will get garbage collected */
6938 o = mono_string_get_pinned (o, error);
6941 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6943 mono_g_hash_table_insert (domain->ldstr_table, o, o);
6955 * Same as mono_ldstr, but return a NULL terminated utf8 string instead
6959 mono_ldstr_utf8 (MonoImage *image, guint32 idx, MonoError *error)
6965 GError *gerror = NULL;
6969 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6970 return NULL; /*FIXME we should probably be raising an exception here*/
6971 str = mono_metadata_user_string (image, idx);
6973 len2 = mono_metadata_decode_blob_size (str, &str);
6976 as = g_utf16_to_utf8 ((guint16*)str, len2, NULL, &written, &gerror);
6978 mono_error_set_argument (error, "string", "%s", gerror->message);
6979 g_error_free (gerror);
6982 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6983 if (len2 > written) {
6984 /* allocate the total length and copy the part of the string that has been converted */
6985 char *as2 = (char *)g_malloc0 (len2);
6986 memcpy (as2, as, written);
6995 * mono_string_to_utf8:
6996 * @s: a System.String
6998 * Returns the UTF8 representation for @s.
6999 * The resulting buffer needs to be freed with mono_free().
7001 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
7004 mono_string_to_utf8 (MonoString *s)
7006 MONO_REQ_GC_UNSAFE_MODE;
7009 char *result = mono_string_to_utf8_checked (s, &error);
7011 if (!is_ok (&error)) {
7012 mono_error_cleanup (&error);
7019 * mono_string_to_utf8_checked:
7020 * @s: a System.String
7021 * @error: a MonoError.
7023 * Converts a MonoString to its UTF8 representation. May fail; check
7024 * @error to determine whether the conversion was successful.
7025 * The resulting buffer should be freed with mono_free().
7028 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
7030 MONO_REQ_GC_UNSAFE_MODE;
7034 GError *gerror = NULL;
7042 return g_strdup ("");
7044 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
7046 mono_error_set_argument (error, "string", "%s", gerror->message);
7047 g_error_free (gerror);
7050 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
7051 if (s->length > written) {
7052 /* allocate the total length and copy the part of the string that has been converted */
7053 char *as2 = (char *)g_malloc0 (s->length);
7054 memcpy (as2, as, written);
7063 mono_string_handle_to_utf8 (MonoStringHandle s, MonoError *error)
7065 return mono_string_to_utf8_checked (MONO_HANDLE_RAW (s), error);
7069 * mono_string_to_utf8_ignore:
7072 * Converts a MonoString to its UTF8 representation. Will ignore
7073 * invalid surrogate pairs.
7074 * The resulting buffer should be freed with mono_free().
7078 mono_string_to_utf8_ignore (MonoString *s)
7080 MONO_REQ_GC_UNSAFE_MODE;
7089 return g_strdup ("");
7091 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
7093 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
7094 if (s->length > written) {
7095 /* allocate the total length and copy the part of the string that has been converted */
7096 char *as2 = (char *)g_malloc0 (s->length);
7097 memcpy (as2, as, written);
7106 * mono_string_to_utf8_image_ignore:
7107 * @s: a System.String
7109 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
7112 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
7114 MONO_REQ_GC_UNSAFE_MODE;
7116 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
7120 * mono_string_to_utf8_mp_ignore:
7121 * @s: a System.String
7123 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
7126 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
7128 MONO_REQ_GC_UNSAFE_MODE;
7130 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
7135 * mono_string_to_utf16:
7138 * Return an null-terminated array of the utf-16 chars
7139 * contained in @s. The result must be freed with g_free().
7140 * This is a temporary helper until our string implementation
7141 * is reworked to always include the null terminating char.
7144 mono_string_to_utf16 (MonoString *s)
7146 MONO_REQ_GC_UNSAFE_MODE;
7153 as = (char *)g_malloc ((s->length * 2) + 2);
7154 as [(s->length * 2)] = '\0';
7155 as [(s->length * 2) + 1] = '\0';
7158 return (gunichar2 *)(as);
7161 memcpy (as, mono_string_chars(s), s->length * 2);
7162 return (gunichar2 *)(as);
7166 * mono_string_to_utf32:
7169 * Return an null-terminated array of the UTF-32 (UCS-4) chars
7170 * contained in @s. The result must be freed with g_free().
7173 mono_string_to_utf32 (MonoString *s)
7175 MONO_REQ_GC_UNSAFE_MODE;
7177 mono_unichar4 *utf32_output = NULL;
7178 GError *error = NULL;
7179 glong items_written;
7184 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
7187 g_error_free (error);
7189 return utf32_output;
7193 * mono_string_from_utf16:
7194 * @data: the UTF16 string (LPWSTR) to convert
7196 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
7198 * Returns: a MonoString.
7201 mono_string_from_utf16 (gunichar2 *data)
7204 MonoString *result = mono_string_from_utf16_checked (data, &error);
7205 mono_error_cleanup (&error);
7210 * mono_string_from_utf16_checked:
7211 * @data: the UTF16 string (LPWSTR) to convert
7212 * @error: set on error
7214 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
7216 * Returns: a MonoString. On failure sets @error and returns NULL.
7219 mono_string_from_utf16_checked (gunichar2 *data, MonoError *error)
7222 MONO_REQ_GC_UNSAFE_MODE;
7225 MonoDomain *domain = mono_domain_get ();
7231 while (data [len]) len++;
7233 return mono_string_new_utf16_checked (domain, data, len, error);
7237 * mono_string_from_utf32:
7238 * @data: the UTF32 string (LPWSTR) to convert
7240 * Converts a UTF32 (UCS-4)to a MonoString.
7242 * Returns: a MonoString.
7245 mono_string_from_utf32 (mono_unichar4 *data)
7248 MonoString *result = mono_string_from_utf32_checked (data, &error);
7249 mono_error_cleanup (&error);
7254 * mono_string_from_utf32_checked:
7255 * @data: the UTF32 string (LPWSTR) to convert
7256 * @error: set on error
7258 * Converts a UTF32 (UCS-4)to a MonoString.
7260 * Returns: a MonoString. On failure returns NULL and sets @error.
7263 mono_string_from_utf32_checked (mono_unichar4 *data, MonoError *error)
7265 MONO_REQ_GC_UNSAFE_MODE;
7268 MonoString* result = NULL;
7269 mono_unichar2 *utf16_output = NULL;
7270 GError *gerror = NULL;
7271 glong items_written;
7277 while (data [len]) len++;
7279 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &gerror);
7282 g_error_free (gerror);
7284 result = mono_string_from_utf16_checked (utf16_output, error);
7285 g_free (utf16_output);
7290 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
7292 MONO_REQ_GC_UNSAFE_MODE;
7299 r = mono_string_to_utf8_ignore (s);
7301 r = mono_string_to_utf8_checked (s, error);
7302 if (!mono_error_ok (error))
7309 len = strlen (r) + 1;
7311 mp_s = (char *)mono_mempool_alloc (mp, len);
7313 mp_s = (char *)mono_image_alloc (image, len);
7315 memcpy (mp_s, r, len);
7323 * mono_string_to_utf8_image:
7324 * @s: a System.String
7326 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
7329 mono_string_to_utf8_image (MonoImage *image, MonoStringHandle s, MonoError *error)
7331 MONO_REQ_GC_UNSAFE_MODE;
7333 return mono_string_to_utf8_internal (NULL, image, MONO_HANDLE_RAW (s), FALSE, error); /* FIXME pin the string */
7337 * mono_string_to_utf8_mp:
7338 * @s: a System.String
7340 * Same as mono_string_to_utf8, but allocate the string from a mempool.
7343 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
7345 MONO_REQ_GC_UNSAFE_MODE;
7347 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
7351 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
7354 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
7356 eh_callbacks = *cbs;
7359 MonoRuntimeExceptionHandlingCallbacks *
7360 mono_get_eh_callbacks (void)
7362 return &eh_callbacks;
7366 * mono_raise_exception:
7367 * @ex: exception object
7369 * Signal the runtime that the exception @ex has been raised in unmanaged code.
7372 mono_raise_exception (MonoException *ex)
7374 MONO_REQ_GC_UNSAFE_MODE;
7377 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
7378 * that will cause gcc to omit the function epilog, causing problems when
7379 * the JIT tries to walk the stack, since the return address on the stack
7380 * will point into the next function in the executable, not this one.
7382 eh_callbacks.mono_raise_exception (ex);
7386 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
7388 MONO_REQ_GC_UNSAFE_MODE;
7390 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
7394 * mono_wait_handle_new:
7395 * @domain: Domain where the object will be created
7396 * @handle: Handle for the wait handle
7397 * @error: set on error.
7399 * Returns: A new MonoWaitHandle created in the given domain for the
7400 * given handle. On failure returns NULL and sets @rror.
7403 mono_wait_handle_new (MonoDomain *domain, HANDLE handle, MonoError *error)
7405 MONO_REQ_GC_UNSAFE_MODE;
7407 MonoWaitHandle *res;
7408 gpointer params [1];
7409 static MonoMethod *handle_set;
7412 res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, error);
7413 return_val_if_nok (error, NULL);
7415 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
7417 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
7419 params [0] = &handle;
7421 mono_runtime_invoke_checked (handle_set, res, params, error);
7426 mono_wait_handle_get_handle (MonoWaitHandle *handle)
7428 MONO_REQ_GC_UNSAFE_MODE;
7430 static MonoClassField *f_safe_handle = NULL;
7433 if (!f_safe_handle) {
7434 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safeWaitHandle");
7435 g_assert (f_safe_handle);
7438 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
7444 mono_runtime_capture_context (MonoDomain *domain, MonoError *error)
7446 MONO_REQ_GC_UNSAFE_MODE;
7448 RuntimeInvokeFunction runtime_invoke;
7452 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
7453 MonoMethod *method = mono_get_context_capture_method ();
7454 MonoMethod *wrapper;
7457 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
7458 domain->capture_context_runtime_invoke = mono_compile_method_checked (wrapper, error);
7459 return_val_if_nok (error, NULL);
7460 domain->capture_context_method = mono_compile_method_checked (method, error);
7461 return_val_if_nok (error, NULL);
7464 runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
7466 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
7469 * mono_async_result_new:
7470 * @domain:domain where the object will be created.
7471 * @handle: wait handle.
7472 * @state: state to pass to AsyncResult
7473 * @data: C closure data.
7474 * @error: set on error.
7476 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
7477 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
7478 * On failure returns NULL and sets @error.
7482 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data, MonoError *error)
7484 MONO_REQ_GC_UNSAFE_MODE;
7487 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, error);
7488 return_val_if_nok (error, NULL);
7489 MonoObject *context = mono_runtime_capture_context (domain, error);
7490 return_val_if_nok (error, NULL);
7491 /* we must capture the execution context from the original thread */
7493 MONO_OBJECT_SETREF (res, execution_context, context);
7494 /* note: result may be null if the flow is suppressed */
7497 res->data = (void **)data;
7498 MONO_OBJECT_SETREF (res, object_data, object_data);
7499 MONO_OBJECT_SETREF (res, async_state, state);
7500 MonoWaitHandle *wait_handle = mono_wait_handle_new (domain, handle, error);
7501 return_val_if_nok (error, NULL);
7503 MONO_OBJECT_SETREF (res, handle, (MonoObject *) wait_handle);
7505 res->sync_completed = FALSE;
7506 res->completed = FALSE;
7512 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
7514 MONO_REQ_GC_UNSAFE_MODE;
7521 g_assert (ares->async_delegate);
7523 ac = (MonoAsyncCall*) ares->object_data;
7525 res = mono_runtime_delegate_invoke_checked (ares->async_delegate, (void**) &ares->async_state, &error);
7526 if (mono_error_set_pending_exception (&error))
7529 gpointer wait_event = NULL;
7531 ac->msg->exc = NULL;
7533 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args, &error);
7535 /* The exit side of the invoke must not be aborted as it would leave the runtime in an undefined state */
7536 mono_threads_begin_abort_protected_block ();
7538 if (!ac->msg->exc) {
7539 MonoException *ex = mono_error_convert_to_exception (&error);
7540 ac->msg->exc = (MonoObject *)ex;
7542 mono_error_cleanup (&error);
7545 MONO_OBJECT_SETREF (ac, res, res);
7547 mono_monitor_enter ((MonoObject*) ares);
7548 ares->completed = 1;
7550 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
7551 mono_monitor_exit ((MonoObject*) ares);
7553 if (wait_event != NULL)
7554 mono_w32event_set (wait_event);
7556 error_init (&error); //the else branch would leave it in an undefined state
7558 mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
7560 mono_threads_end_abort_protected_block ();
7562 if (mono_error_set_pending_exception (&error))
7570 mono_message_init (MonoDomain *domain,
7571 MonoMethodMessage *this_obj,
7572 MonoReflectionMethod *method,
7573 MonoArray *out_args,
7576 MONO_REQ_GC_UNSAFE_MODE;
7578 static MonoMethod *init_message_method = NULL;
7580 if (!init_message_method) {
7581 init_message_method = mono_class_get_method_from_name (mono_defaults.mono_method_message_class, "InitMessage", 2);
7582 g_assert (init_message_method != NULL);
7586 /* FIXME set domain instead? */
7587 g_assert (domain == mono_domain_get ());
7594 mono_runtime_invoke_checked (init_message_method, this_obj, args, error);
7595 return is_ok (error);
7598 #ifndef DISABLE_REMOTING
7600 * mono_remoting_invoke:
7601 * @real_proxy: pointer to a RealProxy object
7602 * @msg: The MonoMethodMessage to execute
7603 * @exc: used to store exceptions
7604 * @out_args: used to store output arguments
7606 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
7607 * IMessage interface and it is not trivial to extract results from there. So
7608 * we call an helper method PrivateInvoke instead of calling
7609 * RealProxy::Invoke() directly.
7611 * Returns: the result object.
7614 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, MonoObject **exc, MonoArray **out_args, MonoError *error)
7616 MONO_REQ_GC_UNSAFE_MODE;
7619 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
7626 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
7629 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
7631 mono_error_set_not_supported (error, "Linked away.");
7634 real_proxy->vtable->domain->private_invoke_method = im;
7637 pa [0] = real_proxy;
7642 o = mono_runtime_try_invoke (im, NULL, pa, exc, error);
7643 return_val_if_nok (error, NULL);
7650 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
7651 MonoObject **exc, MonoArray **out_args, MonoError *error)
7653 MONO_REQ_GC_UNSAFE_MODE;
7655 static MonoClass *object_array_klass;
7660 MonoMethodSignature *sig;
7662 int i, j, outarg_count = 0;
7664 #ifndef DISABLE_REMOTING
7665 if (target && mono_object_is_transparent_proxy (target)) {
7666 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
7667 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7668 target = tp->rp->unwrapped_server;
7670 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args, error);
7675 domain = mono_domain_get ();
7676 method = msg->method->method;
7677 sig = mono_method_signature (method);
7679 for (i = 0; i < sig->param_count; i++) {
7680 if (sig->params [i]->byref)
7684 if (!object_array_klass) {
7687 klass = mono_array_class_get (mono_defaults.object_class, 1);
7690 mono_memory_barrier ();
7691 object_array_klass = klass;
7694 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, error);
7695 return_val_if_nok (error, NULL);
7697 mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
7700 MonoObject *ret = mono_runtime_try_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc, error);
7701 return_val_if_nok (error, NULL);
7703 for (i = 0, j = 0; i < sig->param_count; i++) {
7704 if (sig->params [i]->byref) {
7706 arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
7707 mono_array_setref (*out_args, j, arg);
7716 * prepare_to_string_method:
7718 * @target: Set to @obj or unboxed value if a valuetype
7720 * Returns: the ToString override for @obj. If @obj is a valuetype, @target is unboxed otherwise it's @obj.
7723 prepare_to_string_method (MonoObject *obj, void **target)
7725 MONO_REQ_GC_UNSAFE_MODE;
7727 static MonoMethod *to_string = NULL;
7735 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
7737 method = mono_object_get_virtual_method (obj, to_string);
7739 // Unbox value type if needed
7740 if (mono_class_is_valuetype (mono_method_get_class (method))) {
7741 *target = mono_object_unbox (obj);
7747 * mono_object_to_string:
7749 * @exc: Any exception thrown by ToString (). May be NULL.
7751 * Returns: the result of calling ToString () on an object.
7754 mono_object_to_string (MonoObject *obj, MonoObject **exc)
7757 MonoString *s = NULL;
7759 MonoMethod *method = prepare_to_string_method (obj, &target);
7761 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
7762 if (*exc == NULL && !mono_error_ok (&error))
7763 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
7765 mono_error_cleanup (&error);
7767 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
7768 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
7775 * mono_object_to_string_checked:
7777 * @error: Set on error.
7779 * Returns: the result of calling ToString () on an object. If the
7780 * method cannot be invoked or if it raises an exception, sets @error
7784 mono_object_to_string_checked (MonoObject *obj, MonoError *error)
7788 MonoMethod *method = prepare_to_string_method (obj, &target);
7789 return (MonoString*) mono_runtime_invoke_checked (method, target, NULL, error);
7793 * mono_object_try_to_string:
7795 * @exc: Any exception thrown by ToString (). Must not be NULL.
7796 * @error: Set if method cannot be invoked.
7798 * Returns: the result of calling ToString () on an object. If the
7799 * method cannot be invoked sets @error, if it raises an exception sets @exc,
7803 mono_object_try_to_string (MonoObject *obj, MonoObject **exc, MonoError *error)
7808 MonoMethod *method = prepare_to_string_method (obj, &target);
7809 return (MonoString*) mono_runtime_try_invoke (method, target, NULL, exc, error);
7815 get_native_backtrace (MonoException *exc_raw)
7817 HANDLE_FUNCTION_ENTER ();
7818 MONO_HANDLE_DCL(MonoException, exc);
7819 char * trace = mono_exception_handle_get_native_backtrace (exc);
7820 HANDLE_FUNCTION_RETURN_VAL (trace);
7824 * mono_print_unhandled_exception:
7825 * @exc: The exception
7827 * Prints the unhandled exception.
7830 mono_print_unhandled_exception (MonoObject *exc)
7832 MONO_REQ_GC_UNSAFE_MODE;
7835 char *message = (char*)"";
7836 gboolean free_message = FALSE;
7839 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
7840 message = g_strdup ("OutOfMemoryException");
7841 free_message = TRUE;
7842 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
7843 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
7844 free_message = TRUE;
7847 if (((MonoException*)exc)->native_trace_ips) {
7848 message = get_native_backtrace ((MonoException*)exc);
7849 free_message = TRUE;
7851 MonoObject *other_exc = NULL;
7852 str = mono_object_try_to_string (exc, &other_exc, &error);
7853 if (other_exc == NULL && !is_ok (&error))
7854 other_exc = (MonoObject*)mono_error_convert_to_exception (&error);
7856 mono_error_cleanup (&error);
7858 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
7859 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
7861 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
7862 original_backtrace, nested_backtrace);
7864 g_free (original_backtrace);
7865 g_free (nested_backtrace);
7866 free_message = TRUE;
7868 message = mono_string_to_utf8_checked (str, &error);
7869 if (!mono_error_ok (&error)) {
7870 mono_error_cleanup (&error);
7871 message = (char *) "";
7873 free_message = TRUE;
7880 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
7881 * exc->vtable->klass->name, message);
7883 g_printerr ("\nUnhandled Exception:\n%s\n", message);
7890 * mono_delegate_ctor_with_method:
7891 * @this: pointer to an uninitialized delegate object
7892 * @target: target object
7893 * @addr: pointer to native code
7895 * @error: set on error.
7897 * Initialize a delegate and sets a specific method, not the one
7898 * associated with addr. This is useful when sharing generic code.
7899 * In that case addr will most probably not be associated with the
7900 * correct instantiation of the method.
7901 * On failure returns FALSE and sets @error.
7904 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method, MonoError *error)
7906 MONO_REQ_GC_UNSAFE_MODE;
7909 MonoDelegate *delegate = (MonoDelegate *)this_obj;
7911 g_assert (this_obj);
7914 g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
7917 delegate->method = method;
7919 mono_stats.delegate_creations++;
7921 #ifndef DISABLE_REMOTING
7922 if (target && mono_object_is_transparent_proxy (target)) {
7924 method = mono_marshal_get_remoting_invoke (method);
7925 #ifdef ENABLE_INTERPRETER
7926 g_error ("need RuntimeMethod in method_ptr when using interpreter");
7928 delegate->method_ptr = mono_compile_method_checked (method, error);
7929 return_val_if_nok (error, FALSE);
7930 MONO_OBJECT_SETREF (delegate, target, target);
7934 delegate->method_ptr = addr;
7935 MONO_OBJECT_SETREF (delegate, target, target);
7938 delegate->invoke_impl = callbacks.create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
7939 if (callbacks.init_delegate)
7940 callbacks.init_delegate (delegate);
7945 * mono_delegate_ctor:
7946 * @this: pointer to an uninitialized delegate object
7947 * @target: target object
7948 * @addr: pointer to native code
7949 * @error: set on error.
7951 * This is used to initialize a delegate.
7952 * On failure returns FALSE and sets @error.
7955 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoError *error)
7957 MONO_REQ_GC_UNSAFE_MODE;
7960 MonoDomain *domain = mono_domain_get ();
7962 MonoMethod *method = NULL;
7966 ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
7968 if (!ji && domain != mono_get_root_domain ())
7969 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
7971 method = mono_jit_info_get_method (ji);
7972 g_assert (!mono_class_is_gtd (method->klass));
7975 return mono_delegate_ctor_with_method (this_obj, target, addr, method, error);
7979 * mono_method_call_message_new:
7980 * @method: method to encapsulate
7981 * @params: parameters to the method
7982 * @invoke: optional, delegate invoke.
7983 * @cb: async callback delegate.
7984 * @state: state passed to the async callback.
7985 * @error: set on error.
7987 * Translates arguments pointers into a MonoMethodMessage.
7988 * On failure returns NULL and sets @error.
7991 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
7992 MonoDelegate **cb, MonoObject **state, MonoError *error)
7994 MONO_REQ_GC_UNSAFE_MODE;
7998 MonoDomain *domain = mono_domain_get ();
7999 MonoMethodSignature *sig = mono_method_signature (method);
8000 MonoMethodMessage *msg;
8003 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8004 return_val_if_nok (error, NULL);
8007 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, error);
8008 return_val_if_nok (error, NULL);
8009 mono_message_init (domain, msg, rm, NULL, error);
8010 return_val_if_nok (error, NULL);
8011 count = sig->param_count - 2;
8013 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
8014 return_val_if_nok (error, NULL);
8015 mono_message_init (domain, msg, rm, NULL, error);
8016 return_val_if_nok (error, NULL);
8017 count = sig->param_count;
8020 for (i = 0; i < count; i++) {
8025 if (sig->params [i]->byref)
8026 vpos = *((gpointer *)params [i]);
8030 klass = mono_class_from_mono_type (sig->params [i]);
8032 if (klass->valuetype) {
8033 arg = mono_value_box_checked (domain, klass, vpos, error);
8034 return_val_if_nok (error, NULL);
8036 arg = *((MonoObject **)vpos);
8038 mono_array_setref (msg->args, i, arg);
8041 if (cb != NULL && state != NULL) {
8042 *cb = *((MonoDelegate **)params [i]);
8044 *state = *((MonoObject **)params [i]);
8051 * mono_method_return_message_restore:
8053 * Restore results from message based processing back to arguments pointers
8056 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args, MonoError *error)
8058 MONO_REQ_GC_UNSAFE_MODE;
8062 MonoMethodSignature *sig = mono_method_signature (method);
8063 int i, j, type, size, out_len;
8065 if (out_args == NULL)
8067 out_len = mono_array_length (out_args);
8071 for (i = 0, j = 0; i < sig->param_count; i++) {
8072 MonoType *pt = sig->params [i];
8077 mono_error_set_execution_engine (error, "The proxy call returned an incorrect number of output arguments");
8081 arg = (char *)mono_array_get (out_args, gpointer, j);
8084 g_assert (type != MONO_TYPE_VOID);
8086 if (MONO_TYPE_IS_REFERENCE (pt)) {
8087 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
8090 MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
8091 size = mono_class_value_size (klass, NULL);
8092 if (klass->has_references)
8093 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
8095 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
8097 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
8098 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
8107 #ifndef DISABLE_REMOTING
8110 * mono_load_remote_field:
8111 * @this: pointer to an object
8112 * @klass: klass of the object containing @field
8113 * @field: the field to load
8114 * @res: a storage to store the result
8116 * This method is called by the runtime on attempts to load fields of
8117 * transparent proxy objects. @this points to such TP, @klass is the class of
8118 * the object containing @field. @res is a storage location which can be
8119 * used to store the result.
8121 * Returns: an address pointing to the value of field.
8124 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
8127 gpointer result = mono_load_remote_field_checked (this_obj, klass, field, res, &error);
8128 mono_error_cleanup (&error);
8133 * mono_load_remote_field_checked:
8134 * @this: pointer to an object
8135 * @klass: klass of the object containing @field
8136 * @field: the field to load
8137 * @res: a storage to store the result
8138 * @error: set on error
8140 * This method is called by the runtime on attempts to load fields of
8141 * transparent proxy objects. @this points to such TP, @klass is the class of
8142 * the object containing @field. @res is a storage location which can be
8143 * used to store the result.
8145 * Returns: an address pointing to the value of field. On failure returns NULL and sets @error.
8148 mono_load_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res, MonoError *error)
8150 MONO_REQ_GC_UNSAFE_MODE;
8152 static MonoMethod *getter = NULL;
8156 MonoDomain *domain = mono_domain_get ();
8157 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8158 MonoClass *field_class;
8159 MonoMethodMessage *msg;
8160 MonoArray *out_args;
8164 g_assert (mono_object_is_transparent_proxy (this_obj));
8165 g_assert (res != NULL);
8167 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8168 mono_field_get_value (tp->rp->unwrapped_server, field, res);
8173 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
8175 mono_error_set_not_supported (error, "Linked away.");
8180 field_class = mono_class_from_mono_type (field->type);
8182 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8183 return_val_if_nok (error, NULL);
8184 out_args = mono_array_new_checked (domain, mono_defaults.object_class, 1, error);
8185 return_val_if_nok (error, NULL);
8186 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, error);
8187 return_val_if_nok (error, NULL);
8188 mono_message_init (domain, msg, rm, out_args, error);
8189 return_val_if_nok (error, NULL);
8191 full_name = mono_type_get_full_name (klass);
8192 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
8193 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
8196 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8197 return_val_if_nok (error, NULL);
8200 mono_error_set_exception_instance (error, (MonoException *)exc);
8204 if (mono_array_length (out_args) == 0)
8207 mono_gc_wbarrier_generic_store (res, mono_array_get (out_args, MonoObject *, 0));
8209 if (field_class->valuetype) {
8210 return ((char *)*res) + sizeof (MonoObject);
8216 * mono_load_remote_field_new:
8221 * Missing documentation.
8224 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
8228 MonoObject *result = mono_load_remote_field_new_checked (this_obj, klass, field, &error);
8229 mono_error_cleanup (&error);
8234 * mono_load_remote_field_new_checked:
8235 * @this: pointer to an object
8236 * @klass: klass of the object containing @field
8237 * @field: the field to load
8238 * @error: set on error.
8240 * This method is called by the runtime on attempts to load fields of
8241 * transparent proxy objects. @this points to such TP, @klass is the class of
8242 * the object containing @field.
8244 * Returns: a freshly allocated object containing the value of the field. On failure returns NULL and sets @error.
8247 mono_load_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoError *error)
8249 MONO_REQ_GC_UNSAFE_MODE;
8253 static MonoMethod *tp_load = NULL;
8255 g_assert (mono_object_is_transparent_proxy (this_obj));
8258 tp_load = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "LoadRemoteFieldNew", -1);
8260 mono_error_set_not_supported (error, "Linked away.");
8265 /* MonoType *type = mono_class_get_type (klass); */
8271 return mono_runtime_invoke_checked (tp_load, this_obj, args, error);
8275 * mono_store_remote_field:
8276 * @this_obj: pointer to an object
8277 * @klass: klass of the object containing @field
8278 * @field: the field to load
8279 * @val: the value/object to store
8281 * This method is called by the runtime on attempts to store fields of
8282 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
8283 * the object containing @field. @val is the new value to store in @field.
8286 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
8289 (void) mono_store_remote_field_checked (this_obj, klass, field, val, &error);
8290 mono_error_cleanup (&error);
8294 * mono_store_remote_field_checked:
8295 * @this_obj: pointer to an object
8296 * @klass: klass of the object containing @field
8297 * @field: the field to load
8298 * @val: the value/object to store
8299 * @error: set on error
8301 * This method is called by the runtime on attempts to store fields of
8302 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
8303 * the object containing @field. @val is the new value to store in @field.
8305 * Returns: on success returns TRUE, on failure returns FALSE and sets @error.
8308 mono_store_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val, MonoError *error)
8311 MONO_REQ_GC_UNSAFE_MODE;
8315 MonoDomain *domain = mono_domain_get ();
8316 MonoClass *field_class;
8319 g_assert (mono_object_is_transparent_proxy (this_obj));
8321 field_class = mono_class_from_mono_type (field->type);
8323 if (field_class->valuetype) {
8324 arg = mono_value_box_checked (domain, field_class, val, error);
8325 return_val_if_nok (error, FALSE);
8327 arg = *((MonoObject**)val);
8330 return mono_store_remote_field_new_checked (this_obj, klass, field, arg, error);
8334 * mono_store_remote_field_new:
8340 * Missing documentation
8343 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
8346 (void) mono_store_remote_field_new_checked (this_obj, klass, field, arg, &error);
8347 mono_error_cleanup (&error);
8351 * mono_store_remote_field_new_checked:
8358 * Missing documentation
8361 mono_store_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg, MonoError *error)
8363 MONO_REQ_GC_UNSAFE_MODE;
8365 static MonoMethod *tp_store = NULL;
8369 g_assert (mono_object_is_transparent_proxy (this_obj));
8372 tp_store = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "StoreRemoteField", -1);
8374 mono_error_set_not_supported (error, "Linked away.");
8384 mono_runtime_invoke_checked (tp_store, this_obj, args, error);
8385 return is_ok (error);
8390 * mono_create_ftnptr:
8392 * Given a function address, create a function descriptor for it.
8393 * This is only needed on some platforms.
8396 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
8398 return callbacks.create_ftnptr (domain, addr);
8402 * mono_get_addr_from_ftnptr:
8404 * Given a pointer to a function descriptor, return the function address.
8405 * This is only needed on some platforms.
8408 mono_get_addr_from_ftnptr (gpointer descr)
8410 return callbacks.get_addr_from_ftnptr (descr);
8414 * mono_string_chars:
8417 * Returns a pointer to the UCS16 characters stored in the MonoString
8420 mono_string_chars (MonoString *s)
8422 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
8428 * mono_string_length:
8431 * Returns the lenght in characters of the string
8434 mono_string_length (MonoString *s)
8436 MONO_REQ_GC_UNSAFE_MODE;
8442 * mono_string_handle_length:
8445 * Returns the lenght in characters of the string
8448 mono_string_handle_length (MonoStringHandle s)
8450 MONO_REQ_GC_UNSAFE_MODE;
8452 return MONO_HANDLE_GETVAL (s, length);
8457 * mono_array_length:
8458 * @array: a MonoArray*
8460 * Returns the total number of elements in the array. This works for
8461 * both vectors and multidimensional arrays.
8464 mono_array_length (MonoArray *array)
8466 MONO_REQ_GC_UNSAFE_MODE;
8468 return array->max_length;
8472 * mono_array_addr_with_size:
8473 * @array: a MonoArray*
8474 * @size: size of the array elements
8475 * @idx: index into the array
8477 * Use this function to obtain the address for the @idx item on the
8478 * @array containing elements of size @size.
8480 * This method performs no bounds checking or type checking.
8482 * Returns the address of the @idx element in the array.
8485 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
8487 MONO_REQ_GC_UNSAFE_MODE;
8489 return ((char*)(array)->vector) + size * idx;
8494 mono_glist_to_array (GList *list, MonoClass *eclass, MonoError *error)
8496 MonoDomain *domain = mono_domain_get ();
8504 len = g_list_length (list);
8505 res = mono_array_new_checked (domain, eclass, len, error);
8506 return_val_if_nok (error, NULL);
8508 for (i = 0; list; list = list->next, i++)
8509 mono_array_set (res, gpointer, i, list->data);
8516 * The following section is purely to declare prototypes and
8517 * document the API, as these C files are processed by our
8523 * @array: array to alter
8524 * @element_type: A C type name, this macro will use the sizeof(type) to determine the element size
8525 * @index: index into the array
8526 * @value: value to set
8528 * Value Type version: This sets the @index's element of the @array
8529 * with elements of size sizeof(type) to the provided @value.
8531 * This macro does not attempt to perform type checking or bounds checking.
8533 * Use this to set value types in a `MonoArray`.
8535 void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
8540 * mono_array_setref:
8541 * @array: array to alter
8542 * @index: index into the array
8543 * @value: value to set
8545 * Reference Type version: This sets the @index's element of the
8546 * @array with elements of size sizeof(type) to the provided @value.
8548 * This macro does not attempt to perform type checking or bounds checking.
8550 * Use this to reference types in a `MonoArray`.
8552 void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
8558 * @array: array on which to operate on
8559 * @element_type: C element type (example: MonoString *, int, MonoObject *)
8560 * @index: index into the array
8562 * Use this macro to retrieve the @index element of an @array and
8563 * extract the value assuming that the elements of the array match
8564 * the provided type value.
8566 * This method can be used with both arrays holding value types and
8567 * reference types. For reference types, the @type parameter should
8568 * be a `MonoObject*` or any subclass of it, like `MonoString*`.
8570 * This macro does not attempt to perform type checking or bounds checking.
8572 * Returns: The element at the @index position in the @array.
8574 Type mono_array_get (MonoArray *array, Type element_type, uintptr_t index)