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 gboolean is_blocked = TRUE;
444 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (lock->initializing_tid));
445 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
446 if (mono_native_thread_id_equals (pending_lock->initializing_tid, tid)) {
447 if (!pending_lock->done) {
448 mono_type_initialization_unlock ();
451 /* the thread doing the initialization is blocked on this thread,
452 but on a lock that has already been freed. It just hasn't got
458 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (pending_lock->initializing_tid));
460 ++lock->waiting_count;
461 /* record the fact that we are waiting on the initializing thread */
463 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
465 mono_type_initialization_unlock ();
467 if (do_initialization) {
468 MonoException *exc = NULL;
470 /* We are holding the per-vtable lock, do the actual initialization */
472 mono_threads_begin_abort_protected_block ();
473 mono_runtime_try_invoke (method, NULL, NULL, (MonoObject**) &exc, error);
474 gboolean got_pending_interrupt = mono_threads_end_abort_protected_block ();
476 //exception extracted, error will be set to the right value later
477 if (exc == NULL && !mono_error_ok (error))//invoking failed but exc was not set
478 exc = mono_error_convert_to_exception (error);
480 mono_error_cleanup (error);
484 /* If the initialization failed, mark the class as unusable. */
485 /* Avoid infinite loops */
487 (klass->image == mono_defaults.corlib &&
488 !strcmp (klass->name_space, "System") &&
489 !strcmp (klass->name, "TypeInitializationException")))) {
490 vtable->init_failed = 1;
492 if (klass->name_space && *klass->name_space)
493 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
495 full_name = g_strdup (klass->name);
497 MonoException *exc_to_throw = mono_get_exception_type_initialization_checked (full_name, exc, error);
500 mono_error_assert_ok (error); //We can't recover from this, no way to fail a type we can't alloc a failure.
503 * Store the exception object so it could be thrown on subsequent
506 mono_domain_lock (domain);
507 if (!domain->type_init_exception_hash)
508 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");
509 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
510 mono_domain_unlock (domain);
514 mono_domain_set (last_domain, TRUE);
516 /* Signal to the other threads that we are done */
517 mono_type_init_lock (lock);
519 mono_coop_cond_broadcast (&lock->cond);
520 mono_type_init_unlock (lock);
522 //This can happen if the cctor self-aborts
523 if (exc && mono_object_class (exc) == mono_defaults.threadabortexception_class)
526 //TAEs are blocked around .cctors, they must escape as soon as no cctor is left to run.
527 if (!pending_tae && got_pending_interrupt)
528 pending_tae = mono_thread_try_resume_interruption ();
530 /* this just blocks until the initializing thread is done */
531 mono_type_init_lock (lock);
533 mono_coop_cond_wait (&lock->cond, &lock->mutex);
534 mono_type_init_unlock (lock);
537 /* Do cleanup and setting vtable->initialized inside the global lock again */
538 mono_type_initialization_lock ();
539 if (!do_initialization)
540 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
541 gboolean deleted = unref_type_lock (lock);
543 g_hash_table_remove (type_initialization_hash, vtable);
544 /* Have to set this here since we check it inside the global lock */
545 if (do_initialization && !vtable->init_failed)
546 vtable->initialized = 1;
547 mono_type_initialization_unlock ();
551 mono_error_set_exception_instance (error, pending_tae);
552 else if (vtable->init_failed) {
553 /* Either we were the initializing thread or we waited for the initialization */
554 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
561 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
563 MONO_REQ_GC_NEUTRAL_MODE;
565 MonoVTable *vtable = (MonoVTable*)key;
567 TypeInitializationLock *lock = (TypeInitializationLock*) value;
568 if (mono_native_thread_id_equals (lock->initializing_tid, MONO_UINT_TO_NATIVE_THREAD_ID (GPOINTER_TO_UINT (user))) && !lock->done) {
571 * Have to set this since it cannot be set by the normal code in
572 * mono_runtime_class_init (). In this case, the exception object is not stored,
573 * and get_type_init_exception_for_class () needs to be aware of this.
575 mono_type_init_lock (lock);
576 vtable->init_failed = 1;
577 mono_coop_cond_broadcast (&lock->cond);
578 mono_type_init_unlock (lock);
579 gboolean deleted = unref_type_lock (lock);
587 mono_release_type_locks (MonoInternalThread *thread)
589 MONO_REQ_GC_UNSAFE_MODE;
591 mono_type_initialization_lock ();
592 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, GUINT_TO_POINTER (thread->tid));
593 mono_type_initialization_unlock ();
596 #ifndef DISABLE_REMOTING
599 create_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error)
601 if (!callbacks.create_remoting_trampoline)
602 g_error ("remoting not installed");
603 return callbacks.create_remoting_trampoline (domain, method, target, error);
608 static MonoImtTrampolineBuilder imt_trampoline_builder;
609 static gboolean always_build_imt_trampolines;
611 #if (MONO_IMT_SIZE > 32)
612 #error "MONO_IMT_SIZE cannot be larger than 32"
616 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
618 memcpy (&callbacks, cbs, sizeof (*cbs));
621 MonoRuntimeCallbacks*
622 mono_get_runtime_callbacks (void)
628 mono_install_imt_trampoline_builder (MonoImtTrampolineBuilder func)
630 imt_trampoline_builder = func;
634 mono_set_always_build_imt_trampolines (gboolean value)
636 always_build_imt_trampolines = value;
640 * mono_compile_method:
641 * @method: The method to compile.
643 * This JIT-compiles the method, and returns the pointer to the native code
647 mono_compile_method (MonoMethod *method)
650 gpointer result = mono_compile_method_checked (method, &error);
651 mono_error_cleanup (&error);
656 * mono_compile_method:
657 * @method: The method to compile.
658 * @error: set on error.
660 * This JIT-compiles the method, and returns the pointer to the native code
661 * produced. On failure returns NULL and sets @error.
664 mono_compile_method_checked (MonoMethod *method, MonoError *error)
668 MONO_REQ_GC_NEUTRAL_MODE
672 g_assert (callbacks.compile_method);
673 res = callbacks.compile_method (method, error);
678 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper, MonoError *error)
682 MONO_REQ_GC_NEUTRAL_MODE;
685 res = callbacks.create_jump_trampoline (domain, method, add_sync_wrapper, error);
690 mono_runtime_create_delegate_trampoline (MonoClass *klass)
692 MONO_REQ_GC_NEUTRAL_MODE
694 g_assert (callbacks.create_delegate_trampoline);
695 return callbacks.create_delegate_trampoline (mono_domain_get (), klass);
699 * mono_runtime_free_method:
700 * @domain; domain where the method is hosted
701 * @method: method to release
703 * This routine is invoked to free the resources associated with
704 * a method that has been JIT compiled. This is used to discard
705 * methods that were used only temporarily (for example, used in marshalling)
709 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
711 MONO_REQ_GC_NEUTRAL_MODE
713 if (callbacks.free_method)
714 callbacks.free_method (domain, method);
716 mono_method_clear_object (domain, method);
718 mono_free_method (method);
722 * The vtables in the root appdomain are assumed to be reachable by other
723 * roots, and we don't use typed allocation in the other domains.
726 /* The sync block is no longer a GC pointer */
727 #define GC_HEADER_BITMAP (0)
729 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
732 compute_class_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
734 MONO_REQ_GC_NEUTRAL_MODE;
736 MonoClassField *field;
742 max_size = mono_class_data_size (klass) / sizeof (gpointer);
744 max_size = klass->instance_size / sizeof (gpointer);
745 if (max_size > size) {
746 g_assert (offset <= 0);
747 bitmap = (gsize *)g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
752 /*An Ephemeron cannot be marked by sgen*/
753 if (!static_fields && klass->image == mono_defaults.corlib && !strcmp ("Ephemeron", klass->name)) {
755 memset (bitmap, 0, size / 8);
760 for (p = klass; p != NULL; p = p->parent) {
761 gpointer iter = NULL;
762 while ((field = mono_class_get_fields (p, &iter))) {
766 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
768 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
771 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
774 /* FIXME: should not happen, flag as type load error */
775 if (field->type->byref)
778 if (static_fields && field->offset == -1)
782 pos = field->offset / sizeof (gpointer);
785 type = mono_type_get_underlying_type (field->type);
786 switch (type->type) {
790 case MONO_TYPE_FNPTR:
792 case MONO_TYPE_STRING:
793 case MONO_TYPE_SZARRAY:
794 case MONO_TYPE_CLASS:
795 case MONO_TYPE_OBJECT:
796 case MONO_TYPE_ARRAY:
797 g_assert ((field->offset % sizeof(gpointer)) == 0);
799 g_assert (pos < size || pos <= max_size);
800 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
801 *max_set = MAX (*max_set, pos);
803 case MONO_TYPE_GENERICINST:
804 if (!mono_type_generic_inst_is_valuetype (type)) {
805 g_assert ((field->offset % sizeof(gpointer)) == 0);
807 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
808 *max_set = MAX (*max_set, pos);
813 case MONO_TYPE_VALUETYPE: {
814 MonoClass *fclass = mono_class_from_mono_type (field->type);
815 if (fclass->has_references) {
816 /* remove the object header */
817 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
831 case MONO_TYPE_BOOLEAN:
835 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
846 * mono_class_compute_bitmap:
848 * Mono internal function to compute a bitmap of reference fields in a class.
851 mono_class_compute_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
853 MONO_REQ_GC_NEUTRAL_MODE;
855 return compute_class_bitmap (klass, bitmap, size, offset, max_set, static_fields);
860 * similar to the above, but sets the bits in the bitmap for any non-ref field
861 * and ignores static fields
864 compute_class_non_ref_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset)
866 MonoClassField *field;
871 max_size = class->instance_size / sizeof (gpointer);
872 if (max_size >= size) {
873 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
876 for (p = class; p != NULL; p = p->parent) {
877 gpointer iter = NULL;
878 while ((field = mono_class_get_fields (p, &iter))) {
881 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
883 /* FIXME: should not happen, flag as type load error */
884 if (field->type->byref)
887 pos = field->offset / sizeof (gpointer);
890 type = mono_type_get_underlying_type (field->type);
891 switch (type->type) {
892 #if SIZEOF_VOID_P == 8
896 case MONO_TYPE_FNPTR:
901 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
902 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
903 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
906 #if SIZEOF_VOID_P == 4
910 case MONO_TYPE_FNPTR:
915 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
916 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
917 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
923 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
924 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
925 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
928 case MONO_TYPE_BOOLEAN:
931 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
933 case MONO_TYPE_STRING:
934 case MONO_TYPE_SZARRAY:
935 case MONO_TYPE_CLASS:
936 case MONO_TYPE_OBJECT:
937 case MONO_TYPE_ARRAY:
939 case MONO_TYPE_GENERICINST:
940 if (!mono_type_generic_inst_is_valuetype (type)) {
945 case MONO_TYPE_VALUETYPE: {
946 MonoClass *fclass = mono_class_from_mono_type (field->type);
947 /* remove the object header */
948 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
952 g_assert_not_reached ();
961 * mono_class_insecure_overlapping:
962 * check if a class with explicit layout has references and non-references
963 * fields overlapping.
965 * Returns: TRUE if it is insecure to load the type.
968 mono_class_insecure_overlapping (MonoClass *klass)
972 gsize default_bitmap [4] = {0};
974 gsize default_nrbitmap [4] = {0};
975 int i, insecure = FALSE;
978 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
979 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
981 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
982 int idx = i % (sizeof (bitmap [0]) * 8);
983 if (bitmap [idx] & nrbitmap [idx]) {
988 if (bitmap != default_bitmap)
990 if (nrbitmap != default_nrbitmap)
993 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
1001 ves_icall_string_alloc (int length)
1004 MonoString *str = mono_string_new_size_checked (mono_domain_get (), length, &error);
1005 mono_error_set_pending_exception (&error);
1010 /* LOCKING: Acquires the loader lock */
1012 mono_class_compute_gc_descriptor (MonoClass *klass)
1014 MONO_REQ_GC_NEUTRAL_MODE;
1018 gsize default_bitmap [4] = {0};
1019 static gboolean gcj_inited = FALSE;
1020 MonoGCDescriptor gc_descr;
1023 mono_loader_lock ();
1025 mono_register_jit_icall (ves_icall_object_new_fast, "ves_icall_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
1026 mono_register_jit_icall (ves_icall_string_alloc, "ves_icall_string_alloc", mono_create_icall_signature ("object int"), FALSE);
1029 mono_loader_unlock ();
1033 mono_class_init (klass);
1035 if (klass->gc_descr_inited)
1038 bitmap = default_bitmap;
1039 if (klass == mono_defaults.string_class) {
1040 gc_descr = mono_gc_make_descr_for_string (bitmap, 2);
1041 } else if (klass->rank) {
1042 mono_class_compute_gc_descriptor (klass->element_class);
1043 if (MONO_TYPE_IS_REFERENCE (&klass->element_class->byval_arg)) {
1045 gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
1046 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1047 class->name_space, class->name);*/
1049 /* remove the object header */
1050 bitmap = compute_class_bitmap (klass->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
1051 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));
1052 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1053 class->name_space, class->name);*/
1054 if (bitmap != default_bitmap)
1058 /*static int count = 0;
1061 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1062 gc_descr = mono_gc_make_descr_for_object (bitmap, max_set + 1, klass->instance_size);
1064 if (class->gc_descr == MONO_GC_DESCRIPTOR_NULL)
1065 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
1067 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
1068 if (bitmap != default_bitmap)
1072 /* Publish the data */
1073 mono_loader_lock ();
1074 klass->gc_descr = gc_descr;
1075 mono_memory_barrier ();
1076 klass->gc_descr_inited = TRUE;
1077 mono_loader_unlock ();
1081 * field_is_special_static:
1082 * @fklass: The MonoClass to look up.
1083 * @field: The MonoClassField describing the field.
1085 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1086 * SPECIAL_STATIC_NONE otherwise.
1089 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1091 MONO_REQ_GC_NEUTRAL_MODE;
1094 MonoCustomAttrInfo *ainfo;
1096 ainfo = mono_custom_attrs_from_field_checked (fklass, field, &error);
1097 mono_error_cleanup (&error); /* FIXME don't swallow the error? */
1100 for (i = 0; i < ainfo->num_attrs; ++i) {
1101 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1102 if (klass->image == mono_defaults.corlib) {
1103 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1104 mono_custom_attrs_free (ainfo);
1105 return SPECIAL_STATIC_THREAD;
1107 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1108 mono_custom_attrs_free (ainfo);
1109 return SPECIAL_STATIC_CONTEXT;
1113 mono_custom_attrs_free (ainfo);
1114 return SPECIAL_STATIC_NONE;
1117 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1118 #define mix(a,b,c) { \
1119 a -= c; a ^= rot(c, 4); c += b; \
1120 b -= a; b ^= rot(a, 6); a += c; \
1121 c -= b; c ^= rot(b, 8); b += a; \
1122 a -= c; a ^= rot(c,16); c += b; \
1123 b -= a; b ^= rot(a,19); a += c; \
1124 c -= b; c ^= rot(b, 4); b += a; \
1126 #define final(a,b,c) { \
1127 c ^= b; c -= rot(b,14); \
1128 a ^= c; a -= rot(c,11); \
1129 b ^= a; b -= rot(a,25); \
1130 c ^= b; c -= rot(b,16); \
1131 a ^= c; a -= rot(c,4); \
1132 b ^= a; b -= rot(a,14); \
1133 c ^= b; c -= rot(b,24); \
1137 * mono_method_get_imt_slot:
1139 * The IMT slot is embedded into AOTed code, so this must return the same value
1140 * for the same method across all executions. This means:
1141 * - pointers shouldn't be used as hash values.
1142 * - mono_metadata_str_hash () should be used for hashing strings.
1145 mono_method_get_imt_slot (MonoMethod *method)
1147 MONO_REQ_GC_NEUTRAL_MODE;
1149 MonoMethodSignature *sig;
1151 guint32 *hashes_start, *hashes;
1155 /* This can be used to stress tests the collision code */
1159 * We do this to simplify generic sharing. It will hurt
1160 * performance in cases where a class implements two different
1161 * instantiations of the same generic interface.
1162 * The code in build_imt_slots () depends on this.
1164 if (method->is_inflated)
1165 method = ((MonoMethodInflated*)method)->declaring;
1167 sig = mono_method_signature (method);
1168 hashes_count = sig->param_count + 4;
1169 hashes_start = (guint32 *)malloc (hashes_count * sizeof (guint32));
1170 hashes = hashes_start;
1172 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1173 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1174 method->klass->name_space, method->klass->name, method->name);
1177 /* Initialize hashes */
1178 hashes [0] = mono_metadata_str_hash (method->klass->name);
1179 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1180 hashes [2] = mono_metadata_str_hash (method->name);
1181 hashes [3] = mono_metadata_type_hash (sig->ret);
1182 for (i = 0; i < sig->param_count; i++) {
1183 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1186 /* Setup internal state */
1187 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1189 /* Handle most of the hashes */
1190 while (hashes_count > 3) {
1199 /* Handle the last 3 hashes (all the case statements fall through) */
1200 switch (hashes_count) {
1201 case 3 : c += hashes [2];
1202 case 2 : b += hashes [1];
1203 case 1 : a += hashes [0];
1205 case 0: /* nothing left to add */
1209 g_free (hashes_start);
1210 /* Report the result */
1211 return c % MONO_IMT_SIZE;
1220 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1221 MONO_REQ_GC_NEUTRAL_MODE;
1223 guint32 imt_slot = mono_method_get_imt_slot (method);
1224 MonoImtBuilderEntry *entry;
1226 if (slot_num >= 0 && imt_slot != slot_num) {
1227 /* we build just a single imt slot and this is not it */
1231 entry = (MonoImtBuilderEntry *)g_malloc0 (sizeof (MonoImtBuilderEntry));
1232 entry->key = method;
1233 entry->value.vtable_slot = vtable_slot;
1234 entry->next = imt_builder [imt_slot];
1235 if (imt_builder [imt_slot] != NULL) {
1236 entry->children = imt_builder [imt_slot]->children + 1;
1237 if (entry->children == 1) {
1238 mono_stats.imt_slots_with_collisions++;
1239 *imt_collisions_bitmap |= (1 << imt_slot);
1242 entry->children = 0;
1243 mono_stats.imt_used_slots++;
1245 imt_builder [imt_slot] = entry;
1248 char *method_name = mono_method_full_name (method, TRUE);
1249 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1250 method, method_name, imt_slot, vtable_slot, entry->children);
1251 g_free (method_name);
1258 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1260 MonoMethod *method = e->key;
1261 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1265 method->klass->name_space,
1266 method->klass->name,
1269 printf (" * %s: NULL\n", message);
1275 compare_imt_builder_entries (const void *p1, const void *p2) {
1276 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1277 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1279 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1283 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1285 MONO_REQ_GC_NEUTRAL_MODE;
1287 int count = end - start;
1288 int chunk_start = out_array->len;
1291 for (i = start; i < end; ++i) {
1292 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1293 item->key = sorted_array [i]->key;
1294 item->value = sorted_array [i]->value;
1295 item->has_target_code = sorted_array [i]->has_target_code;
1296 item->is_equals = TRUE;
1298 item->check_target_idx = out_array->len + 1;
1300 item->check_target_idx = 0;
1301 g_ptr_array_add (out_array, item);
1304 int middle = start + count / 2;
1305 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1307 item->key = sorted_array [middle]->key;
1308 item->is_equals = FALSE;
1309 g_ptr_array_add (out_array, item);
1310 imt_emit_ir (sorted_array, start, middle, out_array);
1311 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1317 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1318 MONO_REQ_GC_NEUTRAL_MODE;
1320 int number_of_entries = entries->children + 1;
1321 MonoImtBuilderEntry **sorted_array = (MonoImtBuilderEntry **)malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1322 GPtrArray *result = g_ptr_array_new ();
1323 MonoImtBuilderEntry *current_entry;
1326 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1327 sorted_array [i] = current_entry;
1329 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1331 /*for (i = 0; i < number_of_entries; i++) {
1332 print_imt_entry (" sorted array:", sorted_array [i], i);
1335 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1337 g_free (sorted_array);
1342 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1344 MONO_REQ_GC_NEUTRAL_MODE;
1346 if (imt_builder_entry != NULL) {
1347 if (imt_builder_entry->children == 0 && !fail_tramp && !always_build_imt_trampolines) {
1348 /* No collision, return the vtable slot contents */
1349 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1351 /* Collision, build the trampoline */
1352 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1355 result = imt_trampoline_builder (vtable, domain,
1356 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1357 for (i = 0; i < imt_ir->len; ++i)
1358 g_free (g_ptr_array_index (imt_ir, i));
1359 g_ptr_array_free (imt_ir, TRUE);
1371 static MonoImtBuilderEntry*
1372 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1375 * LOCKING: requires the loader and domain locks.
1379 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1381 MONO_REQ_GC_NEUTRAL_MODE;
1385 guint32 imt_collisions_bitmap = 0;
1386 MonoImtBuilderEntry **imt_builder = (MonoImtBuilderEntry **)calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1387 int method_count = 0;
1388 gboolean record_method_count_for_max_collisions = FALSE;
1389 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1392 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1394 for (i = 0; i < klass->interface_offsets_count; ++i) {
1395 MonoClass *iface = klass->interfaces_packed [i];
1396 int interface_offset = klass->interface_offsets_packed [i];
1397 int method_slot_in_interface, vt_slot;
1399 if (mono_class_has_variant_generic_params (iface))
1400 has_variant_iface = TRUE;
1402 mono_class_setup_methods (iface);
1403 vt_slot = interface_offset;
1404 int mcount = mono_class_get_method_count (iface);
1405 for (method_slot_in_interface = 0; method_slot_in_interface < mcount; method_slot_in_interface++) {
1408 if (slot_num >= 0 && mono_class_is_ginst (iface)) {
1410 * The imt slot of the method is the same as for its declaring method,
1411 * see the comment in mono_method_get_imt_slot (), so we can
1412 * avoid inflating methods which will be discarded by
1413 * add_imt_builder_entry anyway.
1415 method = mono_class_get_method_by_index (mono_class_get_generic_class (iface)->container_class, method_slot_in_interface);
1416 if (mono_method_get_imt_slot (method) != slot_num) {
1421 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1422 if (method->is_generic) {
1423 has_generic_virtual = TRUE;
1428 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1429 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1434 if (extra_interfaces) {
1435 int interface_offset = klass->vtable_size;
1437 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1438 MonoClass* iface = (MonoClass *)list_item->data;
1439 int method_slot_in_interface;
1440 int mcount = mono_class_get_method_count (iface);
1441 for (method_slot_in_interface = 0; method_slot_in_interface < mcount; method_slot_in_interface++) {
1442 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1444 if (method->is_generic)
1445 has_generic_virtual = TRUE;
1446 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1448 interface_offset += mcount;
1451 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1452 /* overwrite the imt slot only if we're building all the entries or if
1453 * we're building this specific one
1455 if (slot_num < 0 || i == slot_num) {
1456 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1459 if (imt_builder [i]) {
1460 MonoImtBuilderEntry *entry;
1462 /* Link entries with imt_builder [i] */
1463 for (entry = entries; entry->next; entry = entry->next) {
1465 MonoMethod *method = (MonoMethod*)entry->key;
1466 char *method_name = mono_method_full_name (method, TRUE);
1467 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1468 g_free (method_name);
1471 entry->next = imt_builder [i];
1472 entries->children += imt_builder [i]->children + 1;
1474 imt_builder [i] = entries;
1477 if (has_generic_virtual || has_variant_iface) {
1479 * There might be collisions later when the the trampoline is expanded.
1481 imt_collisions_bitmap |= (1 << i);
1484 * The IMT trampoline might be called with an instance of one of the
1485 * generic virtual methods, so has to fallback to the IMT trampoline.
1487 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline (vt, i));
1489 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1492 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1496 if (imt_builder [i] != NULL) {
1497 int methods_in_slot = imt_builder [i]->children + 1;
1498 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1499 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1500 record_method_count_for_max_collisions = TRUE;
1502 method_count += methods_in_slot;
1506 mono_stats.imt_number_of_methods += method_count;
1507 if (record_method_count_for_max_collisions) {
1508 mono_stats.imt_method_count_when_max_collisions = method_count;
1511 for (i = 0; i < MONO_IMT_SIZE; i++) {
1512 MonoImtBuilderEntry* entry = imt_builder [i];
1513 while (entry != NULL) {
1514 MonoImtBuilderEntry* next = entry->next;
1519 g_free (imt_builder);
1520 /* we OR the bitmap since we may build just a single imt slot at a time */
1521 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1525 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1526 MONO_REQ_GC_NEUTRAL_MODE;
1528 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1532 * mono_vtable_build_imt_slot:
1533 * @vtable: virtual object table struct
1534 * @imt_slot: slot in the IMT table
1536 * Fill the given @imt_slot in the IMT table of @vtable with
1537 * a trampoline or a trampoline for the case of collisions.
1538 * This is part of the internal mono API.
1540 * LOCKING: Take the domain lock.
1543 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1545 MONO_REQ_GC_NEUTRAL_MODE;
1547 gpointer *imt = (gpointer*)vtable;
1548 imt -= MONO_IMT_SIZE;
1549 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1551 /* no support for extra interfaces: the proxy objects will need
1552 * to build the complete IMT
1553 * Update and heck needs to ahppen inside the proper domain lock, as all
1554 * the changes made to a MonoVTable.
1556 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1557 mono_domain_lock (vtable->domain);
1558 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1559 if (!callbacks.imt_entry_inited (vtable, imt_slot))
1560 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1561 mono_domain_unlock (vtable->domain);
1562 mono_loader_unlock ();
1565 #define THUNK_THRESHOLD 10
1568 * mono_method_alloc_generic_virtual_trampoline:
1570 * @size: size in bytes
1572 * Allocs size bytes to be used for the code of a generic virtual
1573 * trampoline. It's either allocated from the domain's code manager or
1574 * reused from a previously invalidated piece.
1576 * LOCKING: The domain lock must be held.
1579 mono_method_alloc_generic_virtual_trampoline (MonoDomain *domain, int size)
1581 MONO_REQ_GC_NEUTRAL_MODE;
1583 static gboolean inited = FALSE;
1584 static int generic_virtual_trampolines_size = 0;
1587 mono_counters_register ("Generic virtual trampoline bytes",
1588 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_trampolines_size);
1591 generic_virtual_trampolines_size += size;
1593 return mono_domain_code_reserve (domain, size);
1596 typedef struct _GenericVirtualCase {
1600 struct _GenericVirtualCase *next;
1601 } GenericVirtualCase;
1604 * get_generic_virtual_entries:
1606 * Return IMT entries for the generic virtual method instances and
1607 * variant interface methods for vtable slot
1610 static MonoImtBuilderEntry*
1611 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1613 MONO_REQ_GC_NEUTRAL_MODE;
1615 GenericVirtualCase *list;
1616 MonoImtBuilderEntry *entries;
1618 mono_domain_lock (domain);
1619 if (!domain->generic_virtual_cases)
1620 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1622 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1625 for (; list; list = list->next) {
1626 MonoImtBuilderEntry *entry;
1628 if (list->count < THUNK_THRESHOLD)
1631 entry = g_new0 (MonoImtBuilderEntry, 1);
1632 entry->key = list->method;
1633 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1634 entry->has_target_code = 1;
1636 entry->children = entries->children + 1;
1637 entry->next = entries;
1641 mono_domain_unlock (domain);
1643 /* FIXME: Leaking memory ? */
1648 * mono_method_add_generic_virtual_invocation:
1650 * @vtable_slot: pointer to the vtable slot
1651 * @method: the inflated generic virtual method
1652 * @code: the method's code
1654 * Registers a call via unmanaged code to a generic virtual method
1655 * instantiation or variant interface method. If the number of calls reaches a threshold
1656 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1657 * virtual method trampoline.
1660 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1661 gpointer *vtable_slot,
1662 MonoMethod *method, gpointer code)
1664 MONO_REQ_GC_NEUTRAL_MODE;
1666 static gboolean inited = FALSE;
1667 static int num_added = 0;
1668 static int num_freed = 0;
1670 GenericVirtualCase *gvc, *list;
1671 MonoImtBuilderEntry *entries;
1675 mono_domain_lock (domain);
1676 if (!domain->generic_virtual_cases)
1677 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1680 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1681 mono_counters_register ("Freed IMT trampolines", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_freed);
1685 /* Check whether the case was already added */
1686 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1689 if (gvc->method == method)
1694 /* If not found, make a new one */
1696 gvc = (GenericVirtualCase *)mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1697 gvc->method = method;
1700 gvc->next = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1702 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1707 if (++gvc->count == THUNK_THRESHOLD) {
1708 gpointer *old_thunk = (void **)*vtable_slot;
1709 gpointer vtable_trampoline = NULL;
1710 gpointer imt_trampoline = NULL;
1712 if ((gpointer)vtable_slot < (gpointer)vtable) {
1713 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1714 int imt_slot = MONO_IMT_SIZE + displacement;
1716 /* Force the rebuild of the trampoline at the next call */
1717 imt_trampoline = callbacks.get_imt_trampoline (vtable, imt_slot);
1718 *vtable_slot = imt_trampoline;
1720 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline (vtable, (gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1722 entries = get_generic_virtual_entries (domain, vtable_slot);
1724 sorted = imt_sort_slot_entries (entries);
1726 *vtable_slot = imt_trampoline_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1730 MonoImtBuilderEntry *next = entries->next;
1735 for (i = 0; i < sorted->len; ++i)
1736 g_free (g_ptr_array_index (sorted, i));
1737 g_ptr_array_free (sorted, TRUE);
1739 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1744 mono_domain_unlock (domain);
1747 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error);
1750 * mono_class_vtable:
1751 * @domain: the application domain
1752 * @class: the class to initialize
1754 * VTables are domain specific because we create domain specific code, and
1755 * they contain the domain specific static class data.
1756 * On failure, NULL is returned, and class->exception_type is set.
1759 mono_class_vtable (MonoDomain *domain, MonoClass *klass)
1762 MonoVTable* vtable = mono_class_vtable_full (domain, klass, &error);
1763 mono_error_cleanup (&error);
1768 * mono_class_vtable_full:
1769 * @domain: the application domain
1770 * @class: the class to initialize
1771 * @error set on failure.
1773 * VTables are domain specific because we create domain specific code, and
1774 * they contain the domain specific static class data.
1777 mono_class_vtable_full (MonoDomain *domain, MonoClass *klass, MonoError *error)
1779 MONO_REQ_GC_UNSAFE_MODE;
1781 MonoClassRuntimeInfo *runtime_info;
1787 if (mono_class_has_failure (klass)) {
1788 mono_error_set_for_class_failure (error, klass);
1792 /* this check can be inlined in jitted code, too */
1793 runtime_info = klass->runtime_info;
1794 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1795 return runtime_info->domain_vtables [domain->domain_id];
1796 return mono_class_create_runtime_vtable (domain, klass, error);
1800 * mono_class_try_get_vtable:
1801 * @domain: the application domain
1802 * @class: the class to initialize
1804 * This function tries to get the associated vtable from @class if
1805 * it was already created.
1808 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *klass)
1810 MONO_REQ_GC_NEUTRAL_MODE;
1812 MonoClassRuntimeInfo *runtime_info;
1816 runtime_info = klass->runtime_info;
1817 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1818 return runtime_info->domain_vtables [domain->domain_id];
1823 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1825 MONO_REQ_GC_NEUTRAL_MODE;
1827 size_t alloc_offset;
1830 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1831 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1832 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1834 if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1835 g_assert ((imt_table_bytes & 7) == 4);
1842 return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1846 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error)
1848 MONO_REQ_GC_UNSAFE_MODE;
1851 MonoClassRuntimeInfo *runtime_info, *old_info;
1852 MonoClassField *field;
1854 int i, vtable_slots;
1855 size_t imt_table_bytes;
1857 guint32 vtable_size, class_size;
1859 gpointer *interface_offsets;
1863 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1864 mono_domain_lock (domain);
1865 runtime_info = klass->runtime_info;
1866 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1867 mono_domain_unlock (domain);
1868 mono_loader_unlock ();
1869 return runtime_info->domain_vtables [domain->domain_id];
1871 if (!klass->inited || mono_class_has_failure (klass)) {
1872 if (!mono_class_init (klass) || mono_class_has_failure (klass)) {
1873 mono_domain_unlock (domain);
1874 mono_loader_unlock ();
1875 mono_error_set_for_class_failure (error, klass);
1880 /* Array types require that their element type be valid*/
1881 if (klass->byval_arg.type == MONO_TYPE_ARRAY || klass->byval_arg.type == MONO_TYPE_SZARRAY) {
1882 MonoClass *element_class = klass->element_class;
1883 if (!element_class->inited)
1884 mono_class_init (element_class);
1886 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1887 if (!mono_class_has_failure (element_class) && !element_class->vtable_size)
1888 mono_class_setup_vtable (element_class);
1890 if (mono_class_has_failure (element_class)) {
1891 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1892 if (!mono_class_has_failure (klass))
1893 mono_class_set_type_load_failure (klass, "");
1894 mono_domain_unlock (domain);
1895 mono_loader_unlock ();
1896 mono_error_set_for_class_failure (error, klass);
1902 * For some classes, mono_class_init () already computed klass->vtable_size, and
1903 * that is all that is needed because of the vtable trampolines.
1905 if (!klass->vtable_size)
1906 mono_class_setup_vtable (klass);
1908 if (mono_class_is_ginst (klass) && !klass->vtable)
1909 mono_class_check_vtable_constraints (klass, NULL);
1911 /* Initialize klass->has_finalize */
1912 mono_class_has_finalizer (klass);
1914 if (mono_class_has_failure (klass)) {
1915 mono_domain_unlock (domain);
1916 mono_loader_unlock ();
1917 mono_error_set_for_class_failure (error, klass);
1921 vtable_slots = klass->vtable_size;
1922 /* we add an additional vtable slot to store the pointer to static field data only when needed */
1923 class_size = mono_class_data_size (klass);
1927 if (klass->interface_offsets_count) {
1928 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1929 mono_stats.imt_number_of_tables++;
1930 mono_stats.imt_tables_size += imt_table_bytes;
1932 imt_table_bytes = 0;
1935 vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
1937 mono_stats.used_class_count++;
1938 mono_stats.class_vtable_size += vtable_size;
1940 interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
1941 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1942 g_assert (!((gsize)vt & 7));
1945 vt->rank = klass->rank;
1946 vt->domain = domain;
1948 mono_class_compute_gc_descriptor (klass);
1950 * We can't use typed allocation in the non-root domains, since the
1951 * collector needs the GC descriptor stored in the vtable even after
1952 * the mempool containing the vtable is destroyed when the domain is
1953 * unloaded. An alternative might be to allocate vtables in the GC
1954 * heap, but this does not seem to work (it leads to crashes inside
1955 * libgc). If that approach is tried, two gc descriptors need to be
1956 * allocated for each class: one for the root domain, and one for all
1957 * other domains. The second descriptor should contain a bit for the
1958 * vtable field in MonoObject, since we can no longer assume the
1959 * vtable is reachable by other roots after the appdomain is unloaded.
1961 #ifdef HAVE_BOEHM_GC
1962 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1963 vt->gc_descr = MONO_GC_DESCRIPTOR_NULL;
1966 vt->gc_descr = klass->gc_descr;
1968 gc_bits = mono_gc_get_vtable_bits (klass);
1969 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
1971 vt->gc_bits = gc_bits;
1974 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
1975 if (klass->has_static_refs) {
1976 MonoGCDescriptor statics_gc_descr;
1978 gsize default_bitmap [4] = {0};
1981 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1982 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], klass->name_space, klass->name, class_size);*/
1983 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1984 vt->vtable [klass->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr, MONO_ROOT_SOURCE_STATIC, "managed static variables");
1985 mono_domain_add_class_static_data (domain, klass, vt->vtable [klass->vtable_size], NULL);
1986 if (bitmap != default_bitmap)
1989 vt->vtable [klass->vtable_size] = mono_domain_alloc0 (domain, class_size);
1991 vt->has_static_fields = TRUE;
1992 mono_stats.class_static_data_size += class_size;
1996 while ((field = mono_class_get_fields (klass, &iter))) {
1997 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1999 if (mono_field_is_deleted (field))
2001 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2002 gint32 special_static = klass->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (klass, field);
2003 if (special_static != SPECIAL_STATIC_NONE) {
2004 guint32 size, offset;
2006 gsize default_bitmap [4] = {0};
2011 if (mono_type_is_reference (field->type)) {
2012 default_bitmap [0] = 1;
2014 bitmap = default_bitmap;
2015 } else if (mono_type_is_struct (field->type)) {
2016 fclass = mono_class_from_mono_type (field->type);
2017 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
2018 numbits = max_set + 1;
2020 default_bitmap [0] = 0;
2022 bitmap = default_bitmap;
2024 size = mono_type_size (field->type, &align);
2025 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
2026 if (!domain->special_static_fields)
2027 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2028 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2029 if (bitmap != default_bitmap)
2032 * This marks the field as special static to speed up the
2033 * checks in mono_field_static_get/set_value ().
2039 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2040 MonoClass *fklass = mono_class_from_mono_type (field->type);
2041 const char *data = mono_field_get_data (field);
2043 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2044 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2045 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2048 if (fklass->valuetype) {
2049 memcpy (t, data, mono_class_value_size (fklass, NULL));
2051 /* it's a pointer type: add check */
2052 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2059 vt->max_interface_id = klass->max_interface_id;
2060 vt->interface_bitmap = klass->interface_bitmap;
2062 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2063 // class->name, klass->interface_offsets_count);
2065 /* Initialize vtable */
2066 if (callbacks.get_vtable_trampoline) {
2067 // This also covers the AOT case
2068 for (i = 0; i < klass->vtable_size; ++i) {
2069 vt->vtable [i] = callbacks.get_vtable_trampoline (vt, i);
2072 mono_class_setup_vtable (klass);
2074 for (i = 0; i < klass->vtable_size; ++i) {
2077 cm = klass->vtable [i];
2079 vt->vtable [i] = callbacks.create_jit_trampoline (domain, cm, error);
2080 if (!is_ok (error)) {
2081 mono_domain_unlock (domain);
2082 mono_loader_unlock ();
2089 if (imt_table_bytes) {
2090 /* Now that the vtable is full, we can actually fill up the IMT */
2091 for (i = 0; i < MONO_IMT_SIZE; ++i)
2092 interface_offsets [i] = callbacks.get_imt_trampoline (vt, i);
2096 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2097 * re-acquire them and check if another thread has created the vtable in the meantime.
2099 /* Special case System.MonoType to avoid infinite recursion */
2100 if (klass != mono_defaults.runtimetype_class) {
2101 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2102 if (!is_ok (error)) {
2103 mono_domain_unlock (domain);
2104 mono_loader_unlock ();
2108 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2109 /* This is unregistered in
2110 unregister_vtable_reflection_type() in
2112 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2115 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (klass));
2117 /* class_vtable_array keeps an array of created vtables
2119 g_ptr_array_add (domain->class_vtable_array, vt);
2120 /* klass->runtime_info is protected by the loader lock, both when
2121 * it it enlarged and when it is stored info.
2125 * Store the vtable in klass->runtime_info.
2126 * klass->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2128 mono_memory_barrier ();
2130 old_info = klass->runtime_info;
2131 if (old_info && old_info->max_domain >= domain->domain_id) {
2132 /* someone already created a large enough runtime info */
2133 old_info->domain_vtables [domain->domain_id] = vt;
2135 int new_size = domain->domain_id;
2137 new_size = MAX (new_size, old_info->max_domain);
2139 /* make the new size a power of two */
2141 while (new_size > i)
2144 /* this is a bounded memory retention issue: may want to
2145 * handle it differently when we'll have a rcu-like system.
2147 runtime_info = (MonoClassRuntimeInfo *)mono_image_alloc0 (klass->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2148 runtime_info->max_domain = new_size - 1;
2149 /* copy the stuff from the older info */
2151 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2153 runtime_info->domain_vtables [domain->domain_id] = vt;
2155 mono_memory_barrier ();
2156 klass->runtime_info = runtime_info;
2159 if (klass == mono_defaults.runtimetype_class) {
2160 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2161 if (!is_ok (error)) {
2162 mono_domain_unlock (domain);
2163 mono_loader_unlock ();
2167 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2168 /* This is unregistered in
2169 unregister_vtable_reflection_type() in
2171 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2174 mono_domain_unlock (domain);
2175 mono_loader_unlock ();
2177 /* make sure the parent is initialized */
2178 /*FIXME shouldn't this fail the current type?*/
2180 mono_class_vtable_full (domain, klass->parent, error);
2185 #ifndef DISABLE_REMOTING
2187 * mono_class_proxy_vtable:
2188 * @domain: the application domain
2189 * @remove_class: the remote class
2190 * @error: set on error
2192 * Creates a vtable for transparent proxies. It is basically
2193 * a copy of the real vtable of the class wrapped in @remote_class,
2194 * but all function pointers invoke the remoting functions, and
2195 * vtable->klass points to the transparent proxy class, and not to @class.
2197 * On failure returns NULL and sets @error
2200 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type, MonoError *error)
2202 MONO_REQ_GC_UNSAFE_MODE;
2204 MonoVTable *vt, *pvt;
2205 int i, j, vtsize, extra_interface_vtsize = 0;
2206 guint32 max_interface_id;
2208 GSList *extra_interfaces = NULL;
2209 MonoClass *klass = remote_class->proxy_class;
2210 gpointer *interface_offsets;
2211 uint8_t *bitmap = NULL;
2213 size_t imt_table_bytes;
2215 #ifdef COMPRESSED_INTERFACE_BITMAP
2221 vt = mono_class_vtable (domain, klass);
2222 g_assert (vt); /*FIXME property handle failure*/
2223 max_interface_id = vt->max_interface_id;
2225 /* Calculate vtable space for extra interfaces */
2226 for (j = 0; j < remote_class->interface_count; j++) {
2227 MonoClass* iclass = remote_class->interfaces[j];
2231 /*FIXME test for interfaces with variant generic arguments*/
2232 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, iclass->interface_id))
2233 continue; /* interface implemented by the class */
2234 if (g_slist_find (extra_interfaces, iclass))
2237 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2239 method_count = mono_class_num_methods (iclass);
2241 ifaces = mono_class_get_implemented_interfaces (iclass, error);
2245 for (i = 0; i < ifaces->len; ++i) {
2246 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2247 /*FIXME test for interfaces with variant generic arguments*/
2248 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, ic->interface_id))
2249 continue; /* interface implemented by the class */
2250 if (g_slist_find (extra_interfaces, ic))
2252 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2253 method_count += mono_class_num_methods (ic);
2255 g_ptr_array_free (ifaces, TRUE);
2259 extra_interface_vtsize += method_count * sizeof (gpointer);
2260 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2263 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2264 mono_stats.imt_number_of_tables++;
2265 mono_stats.imt_tables_size += imt_table_bytes;
2267 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer);
2269 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2271 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2272 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2273 g_assert (!((gsize)pvt & 7));
2275 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer));
2277 pvt->klass = mono_defaults.transparent_proxy_class;
2278 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2279 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2281 /* initialize vtable */
2282 mono_class_setup_vtable (klass);
2283 for (i = 0; i < klass->vtable_size; ++i) {
2286 if ((cm = klass->vtable [i])) {
2287 pvt->vtable [i] = create_remoting_trampoline (domain, cm, target_type, error);
2291 pvt->vtable [i] = NULL;
2294 if (mono_class_is_abstract (klass)) {
2295 /* create trampolines for abstract methods */
2296 for (k = klass; k; k = k->parent) {
2298 gpointer iter = NULL;
2299 while ((m = mono_class_get_methods (k, &iter)))
2300 if (!pvt->vtable [m->slot]) {
2301 pvt->vtable [m->slot] = create_remoting_trampoline (domain, m, target_type, error);
2308 pvt->max_interface_id = max_interface_id;
2309 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2310 #ifdef COMPRESSED_INTERFACE_BITMAP
2311 bitmap = (uint8_t *)g_malloc0 (bsize);
2313 bitmap = (uint8_t *)mono_domain_alloc0 (domain, bsize);
2316 for (i = 0; i < klass->interface_offsets_count; ++i) {
2317 int interface_id = klass->interfaces_packed [i]->interface_id;
2318 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2321 if (extra_interfaces) {
2322 int slot = klass->vtable_size;
2328 /* Create trampolines for the methods of the interfaces */
2329 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2330 interf = (MonoClass *)list_item->data;
2332 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2336 while ((cm = mono_class_get_methods (interf, &iter))) {
2337 pvt->vtable [slot + j++] = create_remoting_trampoline (domain, cm, target_type, error);
2342 slot += mono_class_num_methods (interf);
2346 /* Now that the vtable is full, we can actually fill up the IMT */
2347 build_imt (klass, pvt, domain, interface_offsets, extra_interfaces);
2348 if (extra_interfaces) {
2349 g_slist_free (extra_interfaces);
2352 #ifdef COMPRESSED_INTERFACE_BITMAP
2353 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2354 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2355 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2358 pvt->interface_bitmap = bitmap;
2362 if (extra_interfaces)
2363 g_slist_free (extra_interfaces);
2364 #ifdef COMPRESSED_INTERFACE_BITMAP
2370 #endif /* DISABLE_REMOTING */
2373 * mono_class_field_is_special_static:
2375 * Returns whether @field is a thread/context static field.
2378 mono_class_field_is_special_static (MonoClassField *field)
2380 MONO_REQ_GC_NEUTRAL_MODE
2382 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2384 if (mono_field_is_deleted (field))
2386 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2387 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2394 * mono_class_field_get_special_static_type:
2395 * @field: The MonoClassField describing the field.
2397 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2398 * SPECIAL_STATIC_NONE otherwise.
2401 mono_class_field_get_special_static_type (MonoClassField *field)
2403 MONO_REQ_GC_NEUTRAL_MODE
2405 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2406 return SPECIAL_STATIC_NONE;
2407 if (mono_field_is_deleted (field))
2408 return SPECIAL_STATIC_NONE;
2409 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2410 return field_is_special_static (field->parent, field);
2411 return SPECIAL_STATIC_NONE;
2415 * mono_class_has_special_static_fields:
2417 * Returns whenever @klass has any thread/context static fields.
2420 mono_class_has_special_static_fields (MonoClass *klass)
2422 MONO_REQ_GC_NEUTRAL_MODE
2424 MonoClassField *field;
2428 while ((field = mono_class_get_fields (klass, &iter))) {
2429 g_assert (field->parent == klass);
2430 if (mono_class_field_is_special_static (field))
2437 #ifndef DISABLE_REMOTING
2439 * create_remote_class_key:
2440 * Creates an array of pointers that can be used as a hash key for a remote class.
2441 * The first element of the array is the number of pointers.
2444 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2446 MONO_REQ_GC_NEUTRAL_MODE;
2451 if (remote_class == NULL) {
2452 if (mono_class_is_interface (extra_class)) {
2453 key = (void **)g_malloc (sizeof(gpointer) * 3);
2454 key [0] = GINT_TO_POINTER (2);
2455 key [1] = mono_defaults.marshalbyrefobject_class;
2456 key [2] = extra_class;
2458 key = (void **)g_malloc (sizeof(gpointer) * 2);
2459 key [0] = GINT_TO_POINTER (1);
2460 key [1] = extra_class;
2463 if (extra_class != NULL && mono_class_is_interface (extra_class)) {
2464 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2465 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2466 key [1] = remote_class->proxy_class;
2468 // Keep the list of interfaces sorted
2469 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2470 if (extra_class && remote_class->interfaces [i] > extra_class) {
2471 key [j++] = extra_class;
2474 key [j] = remote_class->interfaces [i];
2477 key [j] = extra_class;
2479 // Replace the old class. The interface list is the same
2480 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2481 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2482 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2483 for (i = 0; i < remote_class->interface_count; i++)
2484 key [2 + i] = remote_class->interfaces [i];
2492 * copy_remote_class_key:
2494 * Make a copy of KEY in the domain and return the copy.
2497 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2499 MONO_REQ_GC_NEUTRAL_MODE
2501 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2502 gpointer *mp_key = (gpointer *)mono_domain_alloc (domain, key_size);
2504 memcpy (mp_key, key, key_size);
2510 * mono_remote_class:
2511 * @domain: the application domain
2512 * @class_name: name of the remote class
2513 * @error: set on error
2515 * Creates and initializes a MonoRemoteClass object for a remote type.
2517 * On failure returns NULL and sets @error
2520 mono_remote_class (MonoDomain *domain, MonoStringHandle class_name, MonoClass *proxy_class, MonoError *error)
2522 MONO_REQ_GC_UNSAFE_MODE;
2524 MonoRemoteClass *rc;
2525 gpointer* key, *mp_key;
2530 key = create_remote_class_key (NULL, proxy_class);
2532 mono_domain_lock (domain);
2533 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2537 mono_domain_unlock (domain);
2541 name = mono_string_to_utf8_mp (domain->mp, MONO_HANDLE_RAW (class_name), error);
2542 if (!is_ok (error)) {
2544 mono_domain_unlock (domain);
2548 mp_key = copy_remote_class_key (domain, key);
2552 if (mono_class_is_interface (proxy_class)) {
2553 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2554 rc->interface_count = 1;
2555 rc->interfaces [0] = proxy_class;
2556 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2558 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2559 rc->interface_count = 0;
2560 rc->proxy_class = proxy_class;
2563 rc->default_vtable = NULL;
2564 rc->xdomain_vtable = NULL;
2565 rc->proxy_class_name = name;
2566 #ifndef DISABLE_PERFCOUNTERS
2567 mono_perfcounters->loader_bytes += mono_string_length (MONO_HANDLE_RAW (class_name)) + 1;
2570 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2572 mono_domain_unlock (domain);
2577 * clone_remote_class:
2578 * Creates a copy of the remote_class, adding the provided class or interface
2580 static MonoRemoteClass*
2581 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2583 MONO_REQ_GC_NEUTRAL_MODE;
2585 MonoRemoteClass *rc;
2586 gpointer* key, *mp_key;
2588 key = create_remote_class_key (remote_class, extra_class);
2589 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2595 mp_key = copy_remote_class_key (domain, key);
2599 if (mono_class_is_interface (extra_class)) {
2601 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2602 rc->proxy_class = remote_class->proxy_class;
2603 rc->interface_count = remote_class->interface_count + 1;
2605 // Keep the list of interfaces sorted, since the hash key of
2606 // the remote class depends on this
2607 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2608 if (remote_class->interfaces [i] > extra_class && i == j)
2609 rc->interfaces [j++] = extra_class;
2610 rc->interfaces [j] = remote_class->interfaces [i];
2613 rc->interfaces [j] = extra_class;
2615 // Replace the old class. The interface array is the same
2616 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2617 rc->proxy_class = extra_class;
2618 rc->interface_count = remote_class->interface_count;
2619 if (rc->interface_count > 0)
2620 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2623 rc->default_vtable = NULL;
2624 rc->xdomain_vtable = NULL;
2625 rc->proxy_class_name = remote_class->proxy_class_name;
2627 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2633 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxyHandle rp, MonoError *error)
2635 MONO_REQ_GC_UNSAFE_MODE;
2639 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2640 mono_domain_lock (domain);
2641 gint32 target_domain_id = MONO_HANDLE_GETVAL (rp, target_domain_id);
2642 if (target_domain_id != -1) {
2643 if (remote_class->xdomain_vtable == NULL)
2644 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN, error);
2645 mono_domain_unlock (domain);
2646 mono_loader_unlock ();
2647 return_val_if_nok (error, NULL);
2648 return remote_class->xdomain_vtable;
2650 if (remote_class->default_vtable == NULL) {
2651 MonoReflectionTypeHandle reftype = MONO_HANDLE_NEW (MonoReflectionType, NULL);
2652 MONO_HANDLE_GET (reftype, rp, class_to_proxy);
2654 MonoType *type = MONO_HANDLE_GETVAL (reftype, type);
2655 MonoClass *klass = mono_class_from_mono_type (type);
2657 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)))
2658 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP, error);
2661 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN, error);
2662 /* N.B. both branches of the if modify error */
2663 if (!is_ok (error)) {
2664 mono_domain_unlock (domain);
2665 mono_loader_unlock ();
2670 mono_domain_unlock (domain);
2671 mono_loader_unlock ();
2672 return remote_class->default_vtable;
2676 * mono_upgrade_remote_class:
2677 * @domain: the application domain
2678 * @tproxy: the proxy whose remote class has to be upgraded.
2679 * @klass: class to which the remote class can be casted.
2680 * @error: set on error
2682 * Updates the vtable of the remote class by adding the necessary method slots
2683 * and interface offsets so it can be safely casted to klass. klass can be a
2684 * class or an interface. On success returns TRUE, on failure returns FALSE and sets @error.
2687 mono_upgrade_remote_class (MonoDomain *domain, MonoObjectHandle proxy_object, MonoClass *klass, MonoError *error)
2689 MONO_REQ_GC_UNSAFE_MODE;
2693 MonoTransparentProxyHandle tproxy = MONO_HANDLE_CAST (MonoTransparentProxy, proxy_object);
2694 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (tproxy, remote_class);
2696 gboolean redo_vtable;
2697 if (mono_class_is_interface (klass)) {
2700 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2701 if (remote_class->interfaces [i] == klass)
2702 redo_vtable = FALSE;
2705 redo_vtable = (remote_class->proxy_class != klass);
2708 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2709 mono_domain_lock (domain);
2711 MonoRemoteClass *fresh_remote_class = clone_remote_class (domain, remote_class, klass);
2712 MONO_HANDLE_SETVAL (tproxy, remote_class, MonoRemoteClass*, fresh_remote_class);
2713 MonoRealProxyHandle real_proxy = MONO_HANDLE_NEW (MonoRealProxy, NULL);
2714 MONO_HANDLE_GET (real_proxy, tproxy, rp);
2715 MONO_HANDLE_SETVAL (proxy_object, vtable, MonoVTable*, mono_remote_class_vtable (domain, fresh_remote_class, real_proxy, error));
2721 mono_domain_unlock (domain);
2722 mono_loader_unlock ();
2723 return is_ok (error);
2725 #endif /* DISABLE_REMOTING */
2729 * mono_object_get_virtual_method:
2730 * @obj: object to operate on.
2733 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2734 * the instance of a callvirt of method.
2737 mono_object_get_virtual_method (MonoObject *obj_raw, MonoMethod *method)
2739 MONO_REQ_GC_UNSAFE_MODE;
2740 HANDLE_FUNCTION_ENTER ();
2742 MONO_HANDLE_DCL (MonoObject, obj);
2743 MonoMethod *result = mono_object_handle_get_virtual_method (obj, method, &error);
2744 mono_error_assert_ok (&error);
2745 HANDLE_FUNCTION_RETURN_VAL (result);
2749 * mono_object_get_virtual_method:
2750 * @obj: object to operate on.
2753 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2754 * the instance of a callvirt of method.
2757 mono_object_handle_get_virtual_method (MonoObjectHandle obj, MonoMethod *method, MonoError *error)
2761 gboolean is_proxy = FALSE;
2762 MonoClass *klass = mono_handle_class (obj);
2763 if (mono_class_is_transparent_proxy (klass)) {
2764 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), remote_class);
2765 klass = remote_class->proxy_class;
2768 return class_get_virtual_method (klass, method, is_proxy, error);
2772 class_get_virtual_method (MonoClass *klass, MonoMethod *method, gboolean is_proxy, MonoError *error)
2777 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2780 mono_class_setup_vtable (klass);
2781 MonoMethod **vtable = klass->vtable;
2783 if (method->slot == -1) {
2784 /* method->slot might not be set for instances of generic methods */
2785 if (method->is_inflated) {
2786 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2787 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2790 g_assert_not_reached ();
2794 MonoMethod *res = NULL;
2795 /* check method->slot is a valid index: perform isinstance? */
2796 if (method->slot != -1) {
2797 if (mono_class_is_interface (method->klass)) {
2799 gboolean variance_used = FALSE;
2800 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2801 g_assert (iface_offset > 0);
2802 res = vtable [iface_offset + method->slot];
2805 res = vtable [method->slot];
2809 #ifndef DISABLE_REMOTING
2811 /* It may be an interface, abstract class method or generic method */
2812 if (!res || mono_method_signature (res)->generic_param_count)
2815 /* generic methods demand invoke_with_check */
2816 if (mono_method_signature (res)->generic_param_count)
2817 res = mono_marshal_get_remoting_invoke_with_check (res);
2820 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2821 res = mono_cominterop_get_invoke (res);
2824 res = mono_marshal_get_remoting_invoke (res);
2829 if (method->is_inflated) {
2830 /* Have to inflate the result */
2831 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, error);
2839 do_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2841 MONO_REQ_GC_UNSAFE_MODE;
2843 MonoObject *result = NULL;
2845 g_assert (callbacks.runtime_invoke);
2849 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2850 mono_profiler_method_start_invoke (method);
2852 result = callbacks.runtime_invoke (method, obj, params, exc, error);
2854 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2855 mono_profiler_method_end_invoke (method);
2857 if (!mono_error_ok (error))
2864 * mono_runtime_invoke:
2865 * @method: method to invoke
2866 * @obJ: object instance
2867 * @params: arguments to the method
2868 * @exc: exception information.
2870 * Invokes the method represented by @method on the object @obj.
2872 * obj is the 'this' pointer, it should be NULL for static
2873 * methods, a MonoObject* for object instances and a pointer to
2874 * the value type for value types.
2876 * The params array contains the arguments to the method with the
2877 * same convention: MonoObject* pointers for object instances and
2878 * pointers to the value type otherwise.
2880 * From unmanaged code you'll usually use the
2881 * mono_runtime_invoke() variant.
2883 * Note that this function doesn't handle virtual methods for
2884 * you, it will exec the exact method you pass: we still need to
2885 * expose a function to lookup the derived class implementation
2886 * of a virtual method (there are examples of this in the code,
2889 * You can pass NULL as the exc argument if you don't want to
2890 * catch exceptions, otherwise, *exc will be set to the exception
2891 * thrown, if any. if an exception is thrown, you can't use the
2892 * MonoObject* result from the function.
2894 * If the method returns a value type, it is boxed in an object
2898 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2903 res = mono_runtime_try_invoke (method, obj, params, exc, &error);
2904 if (*exc == NULL && !mono_error_ok(&error)) {
2905 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
2907 mono_error_cleanup (&error);
2909 res = mono_runtime_invoke_checked (method, obj, params, &error);
2910 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
2916 * mono_runtime_try_invoke:
2917 * @method: method to invoke
2918 * @obJ: object instance
2919 * @params: arguments to the method
2920 * @exc: exception information.
2921 * @error: set on error
2923 * Invokes the method represented by @method on the object @obj.
2925 * obj is the 'this' pointer, it should be NULL for static
2926 * methods, a MonoObject* for object instances and a pointer to
2927 * the value type for value types.
2929 * The params array contains the arguments to the method with the
2930 * same convention: MonoObject* pointers for object instances and
2931 * pointers to the value type otherwise.
2933 * From unmanaged code you'll usually use the
2934 * mono_runtime_invoke() variant.
2936 * Note that this function doesn't handle virtual methods for
2937 * you, it will exec the exact method you pass: we still need to
2938 * expose a function to lookup the derived class implementation
2939 * of a virtual method (there are examples of this in the code,
2942 * For this function, you must not pass NULL as the exc argument if
2943 * you don't want to catch exceptions, use
2944 * mono_runtime_invoke_checked(). If an exception is thrown, you
2945 * can't use the MonoObject* result from the function.
2947 * If this method cannot be invoked, @error will be set and @exc and
2948 * the return value must not be used.
2950 * If the method returns a value type, it is boxed in an object
2954 mono_runtime_try_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError* error)
2956 MONO_REQ_GC_UNSAFE_MODE;
2958 g_assert (exc != NULL);
2960 if (mono_runtime_get_no_exec ())
2961 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2963 return do_runtime_invoke (method, obj, params, exc, error);
2967 * mono_runtime_invoke_checked:
2968 * @method: method to invoke
2969 * @obJ: object instance
2970 * @params: arguments to the method
2971 * @error: set on error
2973 * Invokes the method represented by @method on the object @obj.
2975 * obj is the 'this' pointer, it should be NULL for static
2976 * methods, a MonoObject* for object instances and a pointer to
2977 * the value type for value types.
2979 * The params array contains the arguments to the method with the
2980 * same convention: MonoObject* pointers for object instances and
2981 * pointers to the value type otherwise.
2983 * From unmanaged code you'll usually use the
2984 * mono_runtime_invoke() variant.
2986 * Note that this function doesn't handle virtual methods for
2987 * you, it will exec the exact method you pass: we still need to
2988 * expose a function to lookup the derived class implementation
2989 * of a virtual method (there are examples of this in the code,
2992 * If an exception is thrown, you can't use the MonoObject* result
2993 * from the function.
2995 * If this method cannot be invoked, @error will be set. If the
2996 * method throws an exception (and we're in coop mode) the exception
2997 * will be set in @error.
2999 * If the method returns a value type, it is boxed in an object
3003 mono_runtime_invoke_checked (MonoMethod *method, void *obj, void **params, MonoError* error)
3005 MONO_REQ_GC_UNSAFE_MODE;
3007 if (mono_runtime_get_no_exec ())
3008 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
3010 return do_runtime_invoke (method, obj, params, NULL, error);
3014 * mono_method_get_unmanaged_thunk:
3015 * @method: method to generate a thunk for.
3017 * Returns an unmanaged->managed thunk that can be used to call
3018 * a managed method directly from C.
3020 * The thunk's C signature closely matches the managed signature:
3022 * C#: public bool Equals (object obj);
3023 * C: typedef MonoBoolean (*Equals)(MonoObject*,
3024 * MonoObject*, MonoException**);
3026 * The 1st ("this") parameter must not be used with static methods:
3028 * C#: public static bool ReferenceEquals (object a, object b);
3029 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
3032 * The last argument must be a non-null pointer of a MonoException* pointer.
3033 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
3034 * exception has been thrown in managed code. Otherwise it will point
3035 * to the MonoException* caught by the thunk. In this case, the result of
3036 * the thunk is undefined:
3038 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
3039 * MonoException *ex = NULL;
3040 * Equals func = mono_method_get_unmanaged_thunk (method);
3041 * MonoBoolean res = func (thisObj, objToCompare, &ex);
3043 * // handle exception
3046 * The calling convention of the thunk matches the platform's default
3047 * convention. This means that under Windows, C declarations must
3048 * contain the __stdcall attribute:
3050 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
3051 * MonoObject*, MonoException**);
3055 * Value type arguments and return values are treated as they were objects:
3057 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
3058 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
3060 * Arguments must be properly boxed upon trunk's invocation, while return
3061 * values must be unboxed.
3064 mono_method_get_unmanaged_thunk (MonoMethod *method)
3066 MONO_REQ_GC_NEUTRAL_MODE;
3067 MONO_REQ_API_ENTRYPOINT;
3072 g_assert (!mono_threads_is_coop_enabled ());
3074 MONO_ENTER_GC_UNSAFE;
3075 method = mono_marshal_get_thunk_invoke_wrapper (method);
3076 res = mono_compile_method_checked (method, &error);
3077 mono_error_cleanup (&error);
3078 MONO_EXIT_GC_UNSAFE;
3084 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
3086 MONO_REQ_GC_UNSAFE_MODE;
3090 /* object fields cannot be byref, so we don't need a
3092 gpointer *p = (gpointer*)dest;
3099 case MONO_TYPE_BOOLEAN:
3101 case MONO_TYPE_U1: {
3102 guint8 *p = (guint8*)dest;
3103 *p = value ? *(guint8*)value : 0;
3108 case MONO_TYPE_CHAR: {
3109 guint16 *p = (guint16*)dest;
3110 *p = value ? *(guint16*)value : 0;
3113 #if SIZEOF_VOID_P == 4
3118 case MONO_TYPE_U4: {
3119 gint32 *p = (gint32*)dest;
3120 *p = value ? *(gint32*)value : 0;
3123 #if SIZEOF_VOID_P == 8
3128 case MONO_TYPE_U8: {
3129 gint64 *p = (gint64*)dest;
3130 *p = value ? *(gint64*)value : 0;
3133 case MONO_TYPE_R4: {
3134 float *p = (float*)dest;
3135 *p = value ? *(float*)value : 0;
3138 case MONO_TYPE_R8: {
3139 double *p = (double*)dest;
3140 *p = value ? *(double*)value : 0;
3143 case MONO_TYPE_STRING:
3144 case MONO_TYPE_SZARRAY:
3145 case MONO_TYPE_CLASS:
3146 case MONO_TYPE_OBJECT:
3147 case MONO_TYPE_ARRAY:
3148 mono_gc_wbarrier_generic_store (dest, deref_pointer ? *(MonoObject **)value : (MonoObject *)value);
3150 case MONO_TYPE_FNPTR:
3151 case MONO_TYPE_PTR: {
3152 gpointer *p = (gpointer*)dest;
3153 *p = deref_pointer? *(gpointer*)value: value;
3156 case MONO_TYPE_VALUETYPE:
3157 /* note that 't' and 'type->type' can be different */
3158 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3159 t = mono_class_enum_basetype (type->data.klass)->type;
3162 MonoClass *klass = mono_class_from_mono_type (type);
3163 int size = mono_class_value_size (klass, NULL);
3165 mono_gc_bzero_atomic (dest, size);
3167 mono_gc_wbarrier_value_copy (dest, value, 1, klass);
3170 case MONO_TYPE_GENERICINST:
3171 t = type->data.generic_class->container_class->byval_arg.type;
3174 g_error ("got type %x", type->type);
3179 * mono_field_set_value:
3180 * @obj: Instance object
3181 * @field: MonoClassField describing the field to set
3182 * @value: The value to be set
3184 * Sets the value of the field described by @field in the object instance @obj
3185 * to the value passed in @value. This method should only be used for instance
3186 * fields. For static fields, use mono_field_static_set_value.
3188 * The value must be on the native format of the field type.
3191 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3193 MONO_REQ_GC_UNSAFE_MODE;
3197 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3199 dest = (char*)obj + field->offset;
3200 mono_copy_value (field->type, dest, value, FALSE);
3204 * mono_field_static_set_value:
3205 * @field: MonoClassField describing the field to set
3206 * @value: The value to be set
3208 * Sets the value of the static field described by @field
3209 * to the value passed in @value.
3211 * The value must be on the native format of the field type.
3214 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3216 MONO_REQ_GC_UNSAFE_MODE;
3220 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3221 /* you cant set a constant! */
3222 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3224 if (field->offset == -1) {
3225 /* Special static */
3228 mono_domain_lock (vt->domain);
3229 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3230 mono_domain_unlock (vt->domain);
3231 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3233 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3235 mono_copy_value (field->type, dest, value, FALSE);
3239 * mono_vtable_get_static_field_data:
3241 * Internal use function: return a pointer to the memory holding the static fields
3242 * for a class or NULL if there are no static fields.
3243 * This is exported only for use by the debugger.
3246 mono_vtable_get_static_field_data (MonoVTable *vt)
3248 MONO_REQ_GC_NEUTRAL_MODE
3250 if (!vt->has_static_fields)
3252 return vt->vtable [vt->klass->vtable_size];
3256 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3258 MONO_REQ_GC_UNSAFE_MODE;
3262 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3263 if (field->offset == -1) {
3264 /* Special static */
3267 mono_domain_lock (vt->domain);
3268 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3269 mono_domain_unlock (vt->domain);
3270 src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3272 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3275 src = (guint8*)obj + field->offset;
3282 * mono_field_get_value:
3283 * @obj: Object instance
3284 * @field: MonoClassField describing the field to fetch information from
3285 * @value: pointer to the location where the value will be stored
3287 * Use this routine to get the value of the field @field in the object
3290 * The pointer provided by value must be of the field type, for reference
3291 * types this is a MonoObject*, for value types its the actual pointer to
3296 * mono_field_get_value (obj, int_field, &i);
3299 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3301 MONO_REQ_GC_UNSAFE_MODE;
3307 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3309 src = (char*)obj + field->offset;
3310 mono_copy_value (field->type, value, src, TRUE);
3314 * mono_field_get_value_object:
3315 * @domain: domain where the object will be created (if boxing)
3316 * @field: MonoClassField describing the field to fetch information from
3317 * @obj: The object instance for the field.
3319 * Returns: a new MonoObject with the value from the given field. If the
3320 * field represents a value type, the value is boxed.
3324 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3327 MonoObject* result = mono_field_get_value_object_checked (domain, field, obj, &error);
3328 mono_error_assert_ok (&error);
3333 * mono_field_get_value_object_checked:
3334 * @domain: domain where the object will be created (if boxing)
3335 * @field: MonoClassField describing the field to fetch information from
3336 * @obj: The object instance for the field.
3337 * @error: Set on error.
3339 * Returns: a new MonoObject with the value from the given field. If the
3340 * field represents a value type, the value is boxed. On error returns NULL and sets @error.
3344 mono_field_get_value_object_checked (MonoDomain *domain, MonoClassField *field, MonoObject *obj, MonoError *error)
3346 MONO_REQ_GC_UNSAFE_MODE;
3352 MonoVTable *vtable = NULL;
3354 gboolean is_static = FALSE;
3355 gboolean is_ref = FALSE;
3356 gboolean is_literal = FALSE;
3357 gboolean is_ptr = FALSE;
3358 MonoType *type = mono_field_get_type_checked (field, error);
3360 return_val_if_nok (error, NULL);
3362 switch (type->type) {
3363 case MONO_TYPE_STRING:
3364 case MONO_TYPE_OBJECT:
3365 case MONO_TYPE_CLASS:
3366 case MONO_TYPE_ARRAY:
3367 case MONO_TYPE_SZARRAY:
3372 case MONO_TYPE_BOOLEAN:
3375 case MONO_TYPE_CHAR:
3384 case MONO_TYPE_VALUETYPE:
3385 is_ref = type->byref;
3387 case MONO_TYPE_GENERICINST:
3388 is_ref = !mono_type_generic_inst_is_valuetype (type);
3394 g_error ("type 0x%x not handled in "
3395 "mono_field_get_value_object", type->type);
3399 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3402 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3406 vtable = mono_class_vtable_full (domain, field->parent, error);
3407 return_val_if_nok (error, NULL);
3409 if (!vtable->initialized) {
3410 mono_runtime_class_init_full (vtable, error);
3411 return_val_if_nok (error, NULL);
3420 get_default_field_value (domain, field, &o, error);
3421 return_val_if_nok (error, NULL);
3422 } else if (is_static) {
3423 mono_field_static_get_value_checked (vtable, field, &o, error);
3424 return_val_if_nok (error, NULL);
3426 mono_field_get_value (obj, field, &o);
3432 static MonoMethod *m;
3438 MonoClass *ptr_klass = mono_class_get_pointer_class ();
3439 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3445 get_default_field_value (domain, field, v, error);
3446 return_val_if_nok (error, NULL);
3447 } else if (is_static) {
3448 mono_field_static_get_value_checked (vtable, field, v, error);
3449 return_val_if_nok (error, NULL);
3451 mono_field_get_value (obj, field, v);
3454 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3455 args [0] = ptr ? *ptr : NULL;
3456 args [1] = mono_type_get_object_checked (mono_domain_get (), type, error);
3457 return_val_if_nok (error, NULL);
3459 o = mono_runtime_invoke_checked (m, NULL, args, error);
3460 return_val_if_nok (error, NULL);
3465 /* boxed value type */
3466 klass = mono_class_from_mono_type (type);
3468 if (mono_class_is_nullable (klass))
3469 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass, error);
3471 o = mono_object_new_checked (domain, klass, error);
3472 return_val_if_nok (error, NULL);
3473 v = ((gchar *) o) + sizeof (MonoObject);
3476 get_default_field_value (domain, field, v, error);
3477 return_val_if_nok (error, NULL);
3478 } else if (is_static) {
3479 mono_field_static_get_value_checked (vtable, field, v, error);
3480 return_val_if_nok (error, NULL);
3482 mono_field_get_value (obj, field, v);
3489 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value, MonoError *error)
3491 MONO_REQ_GC_UNSAFE_MODE;
3495 const char *p = blob;
3496 mono_metadata_decode_blob_size (p, &p);
3499 case MONO_TYPE_BOOLEAN:
3502 *(guint8 *) value = *p;
3504 case MONO_TYPE_CHAR:
3507 *(guint16*) value = read16 (p);
3511 *(guint32*) value = read32 (p);
3515 *(guint64*) value = read64 (p);
3518 readr4 (p, (float*) value);
3521 readr8 (p, (double*) value);
3523 case MONO_TYPE_STRING:
3524 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob, error);
3526 case MONO_TYPE_CLASS:
3527 *(gpointer*) value = NULL;
3531 g_warning ("type 0x%02x should not be in constant table", type);
3537 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error)
3539 MONO_REQ_GC_NEUTRAL_MODE;
3541 MonoTypeEnum def_type;
3546 data = mono_class_get_field_default_value (field, &def_type);
3547 mono_get_constant_value_from_blob (domain, def_type, data, value, error);
3551 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3553 MONO_REQ_GC_UNSAFE_MODE;
3559 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3561 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3562 get_default_field_value (vt->domain, field, value, error);
3566 if (field->offset == -1) {
3567 /* Special static */
3568 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3569 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3571 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3573 mono_copy_value (field->type, value, src, TRUE);
3577 * mono_field_static_get_value:
3578 * @vt: vtable to the object
3579 * @field: MonoClassField describing the field to fetch information from
3580 * @value: where the value is returned
3582 * Use this routine to get the value of the static field @field value.
3584 * The pointer provided by value must be of the field type, for reference
3585 * types this is a MonoObject*, for value types its the actual pointer to
3590 * mono_field_static_get_value (vt, int_field, &i);
3593 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3595 MONO_REQ_GC_NEUTRAL_MODE;
3598 mono_field_static_get_value_checked (vt, field, value, &error);
3599 mono_error_cleanup (&error);
3603 * mono_field_static_get_value_checked:
3604 * @vt: vtable to the object
3605 * @field: MonoClassField describing the field to fetch information from
3606 * @value: where the value is returned
3607 * @error: set on error
3609 * Use this routine to get the value of the static field @field value.
3611 * The pointer provided by value must be of the field type, for reference
3612 * types this is a MonoObject*, for value types its the actual pointer to
3617 * mono_field_static_get_value_checked (vt, int_field, &i, error);
3618 * if (!is_ok (error)) { ... }
3620 * On failure sets @error.
3623 mono_field_static_get_value_checked (MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3625 MONO_REQ_GC_NEUTRAL_MODE;
3627 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value, error);
3631 * mono_property_set_value:
3632 * @prop: MonoProperty to set
3633 * @obj: instance object on which to act
3634 * @params: parameters to pass to the propery
3635 * @exc: optional exception
3637 * Invokes the property's set method with the given arguments on the
3638 * object instance obj (or NULL for static properties).
3640 * You can pass NULL as the exc argument if you don't want to
3641 * catch exceptions, otherwise, *exc will be set to the exception
3642 * thrown, if any. if an exception is thrown, you can't use the
3643 * MonoObject* result from the function.
3646 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3648 MONO_REQ_GC_UNSAFE_MODE;
3651 do_runtime_invoke (prop->set, obj, params, exc, &error);
3652 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3653 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3655 mono_error_cleanup (&error);
3660 * mono_property_set_value_checked:
3661 * @prop: MonoProperty to set
3662 * @obj: instance object on which to act
3663 * @params: parameters to pass to the propery
3664 * @error: set on error
3666 * Invokes the property's set method with the given arguments on the
3667 * object instance obj (or NULL for static properties).
3669 * Returns: TRUE on success. On failure returns FALSE and sets @error.
3670 * If an exception is thrown, it will be caught and returned via @error.
3673 mono_property_set_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3675 MONO_REQ_GC_UNSAFE_MODE;
3680 do_runtime_invoke (prop->set, obj, params, &exc, error);
3681 if (exc != NULL && is_ok (error))
3682 mono_error_set_exception_instance (error, (MonoException*)exc);
3683 return is_ok (error);
3687 * mono_property_get_value:
3688 * @prop: MonoProperty to fetch
3689 * @obj: instance object on which to act
3690 * @params: parameters to pass to the propery
3691 * @exc: optional exception
3693 * Invokes the property's get method with the given arguments on the
3694 * object instance obj (or NULL for static properties).
3696 * You can pass NULL as the exc argument if you don't want to
3697 * catch exceptions, otherwise, *exc will be set to the exception
3698 * thrown, if any. if an exception is thrown, you can't use the
3699 * MonoObject* result from the function.
3701 * Returns: the value from invoking the get method on the property.
3704 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3706 MONO_REQ_GC_UNSAFE_MODE;
3709 MonoObject *val = do_runtime_invoke (prop->get, obj, params, exc, &error);
3710 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3711 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3713 mono_error_cleanup (&error); /* FIXME don't raise here */
3720 * mono_property_get_value_checked:
3721 * @prop: MonoProperty to fetch
3722 * @obj: instance object on which to act
3723 * @params: parameters to pass to the propery
3724 * @error: set on error
3726 * Invokes the property's get method with the given arguments on the
3727 * object instance obj (or NULL for static properties).
3729 * If an exception is thrown, you can't use the
3730 * MonoObject* result from the function. The exception will be propagated via @error.
3732 * Returns: the value from invoking the get method on the property. On
3733 * failure returns NULL and sets @error.
3736 mono_property_get_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3738 MONO_REQ_GC_UNSAFE_MODE;
3741 MonoObject *val = do_runtime_invoke (prop->get, obj, params, &exc, error);
3742 if (exc != NULL && !is_ok (error))
3743 mono_error_set_exception_instance (error, (MonoException*) exc);
3751 * mono_nullable_init:
3752 * @buf: The nullable structure to initialize.
3753 * @value: the value to initialize from
3754 * @klass: the type for the object
3756 * Initialize the nullable structure pointed to by @buf from @value which
3757 * should be a boxed value type. The size of @buf should be able to hold
3758 * as much data as the @klass->instance_size (which is the number of bytes
3759 * that will be copies).
3761 * Since Nullables have variable structure, we can not define a C
3762 * structure for them.
3765 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3767 MONO_REQ_GC_UNSAFE_MODE;
3769 MonoClass *param_class = klass->cast_class;
3771 mono_class_setup_fields (klass);
3772 g_assert (klass->fields_inited);
3774 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3775 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3777 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3779 if (param_class->has_references)
3780 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3782 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3784 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3789 * mono_nullable_box:
3790 * @buf: The buffer representing the data to be boxed
3791 * @klass: the type to box it as.
3792 * @error: set on oerr
3794 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3795 * @buf. On failure returns NULL and sets @error
3798 mono_nullable_box (guint8 *buf, MonoClass *klass, MonoError *error)
3800 MONO_REQ_GC_UNSAFE_MODE;
3803 MonoClass *param_class = klass->cast_class;
3805 mono_class_setup_fields (klass);
3806 g_assert (klass->fields_inited);
3808 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3809 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3811 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3812 MonoObject *o = mono_object_new_checked (mono_domain_get (), param_class, error);
3813 return_val_if_nok (error, NULL);
3814 if (param_class->has_references)
3815 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3817 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3825 * mono_get_delegate_invoke:
3826 * @klass: The delegate class
3828 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3831 mono_get_delegate_invoke (MonoClass *klass)
3833 MONO_REQ_GC_NEUTRAL_MODE;
3837 /* This is called at runtime, so avoid the slower search in metadata */
3838 mono_class_setup_methods (klass);
3839 if (mono_class_has_failure (klass))
3841 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3846 * mono_get_delegate_begin_invoke:
3847 * @klass: The delegate class
3849 * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3852 mono_get_delegate_begin_invoke (MonoClass *klass)
3854 MONO_REQ_GC_NEUTRAL_MODE;
3858 /* This is called at runtime, so avoid the slower search in metadata */
3859 mono_class_setup_methods (klass);
3860 if (mono_class_has_failure (klass))
3862 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3867 * mono_get_delegate_end_invoke:
3868 * @klass: The delegate class
3870 * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3873 mono_get_delegate_end_invoke (MonoClass *klass)
3875 MONO_REQ_GC_NEUTRAL_MODE;
3879 /* This is called at runtime, so avoid the slower search in metadata */
3880 mono_class_setup_methods (klass);
3881 if (mono_class_has_failure (klass))
3883 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3888 * mono_runtime_delegate_invoke:
3889 * @delegate: pointer to a delegate object.
3890 * @params: parameters for the delegate.
3891 * @exc: Pointer to the exception result.
3893 * Invokes the delegate method @delegate with the parameters provided.
3895 * You can pass NULL as the exc argument if you don't want to
3896 * catch exceptions, otherwise, *exc will be set to the exception
3897 * thrown, if any. if an exception is thrown, you can't use the
3898 * MonoObject* result from the function.
3901 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3903 MONO_REQ_GC_UNSAFE_MODE;
3907 MonoObject *result = mono_runtime_delegate_try_invoke (delegate, params, exc, &error);
3909 mono_error_cleanup (&error);
3912 if (!is_ok (&error))
3913 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
3917 MonoObject *result = mono_runtime_delegate_invoke_checked (delegate, params, &error);
3918 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
3924 * mono_runtime_delegate_try_invoke:
3925 * @delegate: pointer to a delegate object.
3926 * @params: parameters for the delegate.
3927 * @exc: Pointer to the exception result.
3928 * @error: set on error
3930 * Invokes the delegate method @delegate with the parameters provided.
3932 * You can pass NULL as the exc argument if you don't want to
3933 * catch exceptions, otherwise, *exc will be set to the exception
3934 * thrown, if any. On failure to execute, @error will be set.
3935 * if an exception is thrown, you can't use the
3936 * MonoObject* result from the function.
3939 mono_runtime_delegate_try_invoke (MonoObject *delegate, void **params, MonoObject **exc, MonoError *error)
3941 MONO_REQ_GC_UNSAFE_MODE;
3945 MonoClass *klass = delegate->vtable->klass;
3948 im = mono_get_delegate_invoke (klass);
3950 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3953 o = mono_runtime_try_invoke (im, delegate, params, exc, error);
3955 o = mono_runtime_invoke_checked (im, delegate, params, error);
3962 * mono_runtime_delegate_invoke_checked:
3963 * @delegate: pointer to a delegate object.
3964 * @params: parameters for the delegate.
3965 * @error: set on error
3967 * Invokes the delegate method @delegate with the parameters provided.
3969 * On failure @error will be set and you can't use the MonoObject*
3970 * result from the function.
3973 mono_runtime_delegate_invoke_checked (MonoObject *delegate, void **params, MonoError *error)
3976 return mono_runtime_delegate_try_invoke (delegate, params, NULL, error);
3979 static char **main_args = NULL;
3980 static int num_main_args = 0;
3983 * mono_runtime_get_main_args:
3985 * Returns: a MonoArray with the arguments passed to the main program
3988 mono_runtime_get_main_args (void)
3990 MONO_REQ_GC_UNSAFE_MODE;
3992 MonoArray *result = mono_runtime_get_main_args_checked (&error);
3993 mono_error_assert_ok (&error);
3998 * mono_runtime_get_main_args:
3999 * @error: set on error
4001 * Returns: a MonoArray with the arguments passed to the main
4002 * program. On failure returns NULL and sets @error.
4005 mono_runtime_get_main_args_checked (MonoError *error)
4009 MonoDomain *domain = mono_domain_get ();
4013 res = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, num_main_args, error);
4014 return_val_if_nok (error, NULL);
4016 for (i = 0; i < num_main_args; ++i)
4017 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
4023 free_main_args (void)
4025 MONO_REQ_GC_NEUTRAL_MODE;
4029 for (i = 0; i < num_main_args; ++i)
4030 g_free (main_args [i]);
4037 * mono_runtime_set_main_args:
4038 * @argc: number of arguments from the command line
4039 * @argv: array of strings from the command line
4041 * Set the command line arguments from an embedding application that doesn't otherwise call
4042 * mono_runtime_run_main ().
4045 mono_runtime_set_main_args (int argc, char* argv[])
4047 MONO_REQ_GC_NEUTRAL_MODE;
4052 main_args = g_new0 (char*, argc);
4053 num_main_args = argc;
4055 for (i = 0; i < argc; ++i) {
4058 utf8_arg = mono_utf8_from_external (argv[i]);
4059 if (utf8_arg == NULL) {
4060 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
4061 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4065 main_args [i] = utf8_arg;
4072 * Prepare an array of arguments in order to execute a standard Main()
4073 * method (argc/argv contains the executable name). This method also
4074 * sets the command line argument value needed by System.Environment.
4078 prepare_run_main (MonoMethod *method, int argc, char *argv[])
4080 MONO_REQ_GC_UNSAFE_MODE;
4084 MonoArray *args = NULL;
4085 MonoDomain *domain = mono_domain_get ();
4086 gchar *utf8_fullpath;
4087 MonoMethodSignature *sig;
4089 g_assert (method != NULL);
4091 mono_thread_set_main (mono_thread_current ());
4093 main_args = g_new0 (char*, argc);
4094 num_main_args = argc;
4096 if (!g_path_is_absolute (argv [0])) {
4097 gchar *basename = g_path_get_basename (argv [0]);
4098 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
4102 utf8_fullpath = mono_utf8_from_external (fullpath);
4103 if(utf8_fullpath == NULL) {
4104 /* Printing the arg text will cause glib to
4105 * whinge about "Invalid UTF-8", but at least
4106 * its relevant, and shows the problem text
4109 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
4110 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4117 utf8_fullpath = mono_utf8_from_external (argv[0]);
4118 if(utf8_fullpath == NULL) {
4119 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
4120 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4125 main_args [0] = utf8_fullpath;
4127 for (i = 1; i < argc; ++i) {
4130 utf8_arg=mono_utf8_from_external (argv[i]);
4131 if(utf8_arg==NULL) {
4132 /* Ditto the comment about Invalid UTF-8 here */
4133 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
4134 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4138 main_args [i] = utf8_arg;
4143 sig = mono_method_signature (method);
4145 g_print ("Unable to load Main method.\n");
4149 if (sig->param_count) {
4150 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, argc, &error);
4151 mono_error_assert_ok (&error);
4152 for (i = 0; i < argc; ++i) {
4153 /* The encodings should all work, given that
4154 * we've checked all these args for the
4157 gchar *str = mono_utf8_from_external (argv [i]);
4158 MonoString *arg = mono_string_new (domain, str);
4159 mono_array_setref (args, i, arg);
4163 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, 0, &error);
4164 mono_error_assert_ok (&error);
4167 mono_assembly_set_main (method->klass->image->assembly);
4173 * mono_runtime_run_main:
4174 * @method: the method to start the application with (usually Main)
4175 * @argc: number of arguments from the command line
4176 * @argv: array of strings from the command line
4177 * @exc: excetption results
4179 * Execute a standard Main() method (argc/argv contains the
4180 * executable name). This method also sets the command line argument value
4181 * needed by System.Environment.
4186 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
4189 MONO_REQ_GC_UNSAFE_MODE;
4192 MonoArray *args = prepare_run_main (method, argc, argv);
4195 res = mono_runtime_try_exec_main (method, args, exc);
4197 res = mono_runtime_exec_main_checked (method, args, &error);
4198 mono_error_raise_exception (&error); /* OK to throw, external only without a better alternative */
4204 * mono_runtime_run_main_checked:
4205 * @method: the method to start the application with (usually Main)
4206 * @argc: number of arguments from the command line
4207 * @argv: array of strings from the command line
4208 * @error: set on error
4210 * Execute a standard Main() method (argc/argv contains the
4211 * executable name). This method also sets the command line argument value
4212 * needed by System.Environment. On failure sets @error.
4217 mono_runtime_run_main_checked (MonoMethod *method, int argc, char* argv[],
4221 MonoArray *args = prepare_run_main (method, argc, argv);
4222 return mono_runtime_exec_main_checked (method, args, error);
4226 * mono_runtime_try_run_main:
4227 * @method: the method to start the application with (usually Main)
4228 * @argc: number of arguments from the command line
4229 * @argv: array of strings from the command line
4230 * @exc: set if Main throws an exception
4231 * @error: set if Main can't be executed
4233 * Execute a standard Main() method (argc/argv contains the executable
4234 * name). This method also sets the command line argument value needed
4235 * by System.Environment. On failure sets @error if Main can't be
4236 * executed or @exc if it threw and exception.
4241 mono_runtime_try_run_main (MonoMethod *method, int argc, char* argv[],
4245 MonoArray *args = prepare_run_main (method, argc, argv);
4246 return mono_runtime_try_exec_main (method, args, exc);
4251 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4253 static MonoMethod *serialize_method;
4259 if (!serialize_method) {
4260 MonoClass *klass = mono_class_get_remoting_services_class ();
4261 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
4264 if (!serialize_method) {
4269 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
4274 array = mono_runtime_try_invoke (serialize_method, NULL, params, exc, &error);
4275 if (*exc == NULL && !mono_error_ok (&error))
4276 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert serialize_object to MonoError */
4278 mono_error_cleanup (&error);
4287 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4289 MONO_REQ_GC_UNSAFE_MODE;
4291 static MonoMethod *deserialize_method;
4297 if (!deserialize_method) {
4298 MonoClass *klass = mono_class_get_remoting_services_class ();
4299 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
4301 if (!deserialize_method) {
4309 result = mono_runtime_try_invoke (deserialize_method, NULL, params, exc, &error);
4310 if (*exc == NULL && !mono_error_ok (&error))
4311 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert deserialize_object to MonoError */
4313 mono_error_cleanup (&error);
4321 #ifndef DISABLE_REMOTING
4323 make_transparent_proxy (MonoObject *obj, MonoError *error)
4325 MONO_REQ_GC_UNSAFE_MODE;
4327 static MonoMethod *get_proxy_method;
4329 MonoDomain *domain = mono_domain_get ();
4330 MonoRealProxy *real_proxy;
4331 MonoReflectionType *reflection_type;
4332 MonoTransparentProxy *transparent_proxy;
4336 if (!get_proxy_method)
4337 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
4339 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
4341 real_proxy = (MonoRealProxy*) mono_object_new_checked (domain, mono_defaults.real_proxy_class, error);
4342 return_val_if_nok (error, NULL);
4343 reflection_type = mono_type_get_object_checked (domain, &obj->vtable->klass->byval_arg, error);
4344 return_val_if_nok (error, NULL);
4346 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
4347 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
4349 MonoObject *exc = NULL;
4351 transparent_proxy = (MonoTransparentProxy*) mono_runtime_try_invoke (get_proxy_method, real_proxy, NULL, &exc, error);
4352 if (exc != NULL && is_ok (error))
4353 mono_error_set_exception_instance (error, (MonoException*)exc);
4355 return (MonoObject*) transparent_proxy;
4357 #endif /* DISABLE_REMOTING */
4360 * mono_object_xdomain_representation
4362 * @target_domain: a domain
4363 * @error: set on error.
4365 * Creates a representation of obj in the domain target_domain. This
4366 * is either a copy of obj arrived through via serialization and
4367 * deserialization or a proxy, depending on whether the object is
4368 * serializable or marshal by ref. obj must not be in target_domain.
4370 * If the object cannot be represented in target_domain, NULL is
4371 * returned and @error is set appropriately.
4374 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoError *error)
4376 MONO_REQ_GC_UNSAFE_MODE;
4379 MonoObject *deserialized = NULL;
4381 #ifndef DISABLE_REMOTING
4382 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
4383 deserialized = make_transparent_proxy (obj, error);
4388 gboolean failure = FALSE;
4389 MonoDomain *domain = mono_domain_get ();
4390 MonoObject *serialized;
4391 MonoObject *exc = NULL;
4393 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
4394 serialized = serialize_object (obj, &failure, &exc);
4395 mono_domain_set_internal_with_options (target_domain, FALSE);
4397 deserialized = deserialize_object (serialized, &failure, &exc);
4398 if (domain != target_domain)
4399 mono_domain_set_internal_with_options (domain, FALSE);
4401 mono_error_set_exception_instance (error, (MonoException*)exc);
4404 return deserialized;
4407 /* Used in call_unhandled_exception_delegate */
4409 create_unhandled_exception_eventargs (MonoObject *exc, MonoError *error)
4411 MONO_REQ_GC_UNSAFE_MODE;
4416 MonoMethod *method = NULL;
4417 MonoBoolean is_terminating = TRUE;
4420 klass = mono_class_get_unhandled_exception_event_args_class ();
4421 mono_class_init (klass);
4423 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4424 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
4428 args [1] = &is_terminating;
4430 obj = mono_object_new_checked (mono_domain_get (), klass, error);
4431 return_val_if_nok (error, NULL);
4433 mono_runtime_invoke_checked (method, obj, args, error);
4434 return_val_if_nok (error, NULL);
4439 /* Used in mono_unhandled_exception */
4441 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4442 MONO_REQ_GC_UNSAFE_MODE;
4445 MonoObject *e = NULL;
4447 MonoDomain *current_domain = mono_domain_get ();
4449 if (domain != current_domain)
4450 mono_domain_set_internal_with_options (domain, FALSE);
4452 g_assert (domain == mono_object_domain (domain->domain));
4454 if (mono_object_domain (exc) != domain) {
4456 exc = mono_object_xdomain_representation (exc, domain, &error);
4458 if (!is_ok (&error)) {
4459 MonoError inner_error;
4460 MonoException *serialization_exc = mono_error_convert_to_exception (&error);
4461 exc = mono_object_xdomain_representation ((MonoObject*)serialization_exc, domain, &inner_error);
4462 mono_error_assert_ok (&inner_error);
4464 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4465 "System.Runtime.Serialization", "SerializationException",
4466 "Could not serialize unhandled exception.");
4470 g_assert (mono_object_domain (exc) == domain);
4472 pa [0] = domain->domain;
4473 pa [1] = create_unhandled_exception_eventargs (exc, &error);
4474 mono_error_assert_ok (&error);
4475 mono_runtime_delegate_try_invoke (delegate, pa, &e, &error);
4476 if (!is_ok (&error)) {
4478 e = (MonoObject*)mono_error_convert_to_exception (&error);
4480 mono_error_cleanup (&error);
4483 if (domain != current_domain)
4484 mono_domain_set_internal_with_options (current_domain, FALSE);
4487 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4488 if (!mono_error_ok (&error)) {
4489 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4490 mono_error_cleanup (&error);
4492 g_warning ("exception inside UnhandledException handler: %s\n", msg);
4498 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4501 * mono_runtime_unhandled_exception_policy_set:
4502 * @policy: the new policy
4504 * This is a VM internal routine.
4506 * Sets the runtime policy for handling unhandled exceptions.
4509 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4510 runtime_unhandled_exception_policy = policy;
4514 * mono_runtime_unhandled_exception_policy_get:
4516 * This is a VM internal routine.
4518 * Gets the runtime policy for handling unhandled exceptions.
4520 MonoRuntimeUnhandledExceptionPolicy
4521 mono_runtime_unhandled_exception_policy_get (void) {
4522 return runtime_unhandled_exception_policy;
4526 * mono_unhandled_exception:
4527 * @exc: exception thrown
4529 * This is a VM internal routine.
4531 * We call this function when we detect an unhandled exception
4532 * in the default domain.
4534 * It invokes the * UnhandledException event in AppDomain or prints
4535 * a warning to the console
4538 mono_unhandled_exception (MonoObject *exc)
4540 MONO_REQ_GC_UNSAFE_MODE;
4543 MonoClassField *field;
4544 MonoDomain *current_domain, *root_domain;
4545 MonoObject *current_appdomain_delegate = NULL, *root_appdomain_delegate = NULL;
4547 if (mono_class_has_parent (exc->vtable->klass, mono_defaults.threadabortexception_class))
4550 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4553 current_domain = mono_domain_get ();
4554 root_domain = mono_get_root_domain ();
4556 root_appdomain_delegate = mono_field_get_value_object_checked (root_domain, field, (MonoObject*) root_domain->domain, &error);
4557 mono_error_assert_ok (&error);
4558 if (current_domain != root_domain) {
4559 current_appdomain_delegate = mono_field_get_value_object_checked (current_domain, field, (MonoObject*) current_domain->domain, &error);
4560 mono_error_assert_ok (&error);
4563 if (!current_appdomain_delegate && !root_appdomain_delegate) {
4564 mono_print_unhandled_exception (exc);
4566 /* unhandled exception callbacks must not be aborted */
4567 mono_threads_begin_abort_protected_block ();
4568 if (root_appdomain_delegate)
4569 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4570 if (current_appdomain_delegate)
4571 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4572 mono_threads_end_abort_protected_block ();
4575 /* set exitcode only if we will abort the process */
4576 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4577 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4579 mono_environment_exitcode_set (1);
4584 * mono_runtime_exec_managed_code:
4585 * @domain: Application domain
4586 * @main_func: function to invoke from the execution thread
4587 * @main_args: parameter to the main_func
4589 * Launch a new thread to execute a function
4591 * main_func is called back from the thread with main_args as the
4592 * parameter. The callback function is expected to start Main()
4593 * eventually. This function then waits for all managed threads to
4595 * It is not necesseray anymore to execute managed code in a subthread,
4596 * so this function should not be used anymore by default: just
4597 * execute the code and then call mono_thread_manage ().
4600 mono_runtime_exec_managed_code (MonoDomain *domain,
4601 MonoMainThreadFunc main_func,
4605 mono_thread_create_checked (domain, main_func, main_args, &error);
4606 mono_error_assert_ok (&error);
4608 mono_thread_manage ();
4612 prepare_thread_to_exec_main (MonoDomain *domain, MonoMethod *method)
4614 MonoInternalThread* thread = mono_thread_internal_current ();
4615 MonoCustomAttrInfo* cinfo;
4616 gboolean has_stathread_attribute;
4618 if (!domain->entry_assembly) {
4620 MonoAssembly *assembly;
4622 assembly = method->klass->image->assembly;
4623 domain->entry_assembly = assembly;
4624 /* Domains created from another domain already have application_base and configuration_file set */
4625 if (domain->setup->application_base == NULL) {
4626 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4629 if (domain->setup->configuration_file == NULL) {
4630 str = g_strconcat (assembly->image->name, ".config", NULL);
4631 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4633 mono_domain_set_options_from_config (domain);
4637 MonoError cattr_error;
4638 cinfo = mono_custom_attrs_from_method_checked (method, &cattr_error);
4639 mono_error_cleanup (&cattr_error); /* FIXME warn here? */
4641 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, mono_class_get_sta_thread_attribute_class ());
4643 mono_custom_attrs_free (cinfo);
4645 has_stathread_attribute = FALSE;
4647 if (has_stathread_attribute) {
4648 thread->apartment_state = ThreadApartmentState_STA;
4650 thread->apartment_state = ThreadApartmentState_MTA;
4652 mono_thread_init_apartment_state ();
4657 do_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4659 MONO_REQ_GC_UNSAFE_MODE;
4669 /* FIXME: check signature of method */
4670 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4672 res = mono_runtime_invoke_checked (method, NULL, pa, error);
4674 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4677 mono_environment_exitcode_set (rval);
4679 mono_runtime_invoke_checked (method, NULL, pa, error);
4691 do_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4693 MONO_REQ_GC_UNSAFE_MODE;
4703 /* FIXME: check signature of method */
4704 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4705 MonoError inner_error;
4707 res = mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4708 if (*exc == NULL && !mono_error_ok (&inner_error))
4709 *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4711 mono_error_cleanup (&inner_error);
4714 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4718 mono_environment_exitcode_set (rval);
4720 MonoError inner_error;
4721 mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4722 if (*exc == NULL && !mono_error_ok (&inner_error))
4723 *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4725 mono_error_cleanup (&inner_error);
4730 /* If the return type of Main is void, only
4731 * set the exitcode if an exception was thrown
4732 * (we don't want to blow away an
4733 * explicitly-set exit code)
4736 mono_environment_exitcode_set (rval);
4744 * Execute a standard Main() method (args doesn't contain the
4748 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4751 prepare_thread_to_exec_main (mono_object_domain (args), method);
4753 int rval = do_try_exec_main (method, args, exc);
4756 int rval = do_exec_main_checked (method, args, &error);
4757 mono_error_raise_exception (&error); /* OK to throw, external only with no better option */
4763 * Execute a standard Main() method (args doesn't contain the
4766 * On failure sets @error
4769 mono_runtime_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4772 prepare_thread_to_exec_main (mono_object_domain (args), method);
4773 return do_exec_main_checked (method, args, error);
4777 * Execute a standard Main() method (args doesn't contain the
4780 * On failure sets @error if Main couldn't be executed, or @exc if it threw an exception.
4783 mono_runtime_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4785 prepare_thread_to_exec_main (mono_object_domain (args), method);
4786 return do_try_exec_main (method, args, exc);
4791 /** invoke_array_extract_argument:
4792 * @params: array of arguments to the method.
4793 * @i: the index of the argument to extract.
4794 * @t: ith type from the method signature.
4795 * @has_byref_nullables: outarg - TRUE if method expects a byref nullable argument
4796 * @error: set on error.
4798 * Given an array of method arguments, return the ith one using the corresponding type
4799 * to perform necessary unboxing. If method expects a ref nullable argument, writes TRUE to @has_byref_nullables.
4801 * On failure sets @error and returns NULL.
4804 invoke_array_extract_argument (MonoArray *params, int i, MonoType *t, gboolean* has_byref_nullables, MonoError *error)
4806 MonoType *t_orig = t;
4807 gpointer result = NULL;
4813 case MONO_TYPE_BOOLEAN:
4816 case MONO_TYPE_CHAR:
4825 case MONO_TYPE_VALUETYPE:
4826 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (t_orig))) {
4827 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4828 result = mono_array_get (params, MonoObject*, i);
4830 *has_byref_nullables = TRUE;
4832 /* MS seems to create the objects if a null is passed in */
4833 if (!mono_array_get (params, MonoObject*, i)) {
4834 MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (t_orig), error);
4835 return_val_if_nok (error, NULL);
4836 mono_array_setref (params, i, o);
4841 * We can't pass the unboxed vtype byref to the callee, since
4842 * that would mean the callee would be able to modify boxed
4843 * primitive types. So we (and MS) make a copy of the boxed
4844 * object, pass that to the callee, and replace the original
4845 * boxed object in the arg array with the copy.
4847 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4848 MonoObject *copy = mono_value_box_checked (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig), error);
4849 return_val_if_nok (error, NULL);
4850 mono_array_setref (params, i, copy);
4853 result = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4856 case MONO_TYPE_STRING:
4857 case MONO_TYPE_OBJECT:
4858 case MONO_TYPE_CLASS:
4859 case MONO_TYPE_ARRAY:
4860 case MONO_TYPE_SZARRAY:
4862 result = mono_array_addr (params, MonoObject*, i);
4863 // FIXME: I need to check this code path
4865 result = mono_array_get (params, MonoObject*, i);
4867 case MONO_TYPE_GENERICINST:
4869 t = &t->data.generic_class->container_class->this_arg;
4871 t = &t->data.generic_class->container_class->byval_arg;
4873 case MONO_TYPE_PTR: {
4876 /* The argument should be an IntPtr */
4877 arg = mono_array_get (params, MonoObject*, i);
4881 g_assert (arg->vtable->klass == mono_defaults.int_class);
4882 result = ((MonoIntPtr*)arg)->m_value;
4887 g_error ("type 0x%x not handled in mono_runtime_invoke_array", t_orig->type);
4892 * mono_runtime_invoke_array:
4893 * @method: method to invoke
4894 * @obJ: object instance
4895 * @params: arguments to the method
4896 * @exc: exception information.
4898 * Invokes the method represented by @method on the object @obj.
4900 * obj is the 'this' pointer, it should be NULL for static
4901 * methods, a MonoObject* for object instances and a pointer to
4902 * the value type for value types.
4904 * The params array contains the arguments to the method with the
4905 * same convention: MonoObject* pointers for object instances and
4906 * pointers to the value type otherwise. The _invoke_array
4907 * variant takes a C# object[] as the params argument (MonoArray
4908 * *params): in this case the value types are boxed inside the
4909 * respective reference representation.
4911 * From unmanaged code you'll usually use the
4912 * mono_runtime_invoke_checked() variant.
4914 * Note that this function doesn't handle virtual methods for
4915 * you, it will exec the exact method you pass: we still need to
4916 * expose a function to lookup the derived class implementation
4917 * of a virtual method (there are examples of this in the code,
4920 * You can pass NULL as the exc argument if you don't want to
4921 * catch exceptions, otherwise, *exc will be set to the exception
4922 * thrown, if any. if an exception is thrown, you can't use the
4923 * MonoObject* result from the function.
4925 * If the method returns a value type, it is boxed in an object
4929 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4934 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, exc, &error);
4936 mono_error_cleanup (&error);
4939 if (!is_ok (&error))
4940 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
4944 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, NULL, &error);
4945 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
4951 * mono_runtime_invoke_array_checked:
4952 * @method: method to invoke
4953 * @obJ: object instance
4954 * @params: arguments to the method
4955 * @error: set on failure.
4957 * Invokes the method represented by @method on the object @obj.
4959 * obj is the 'this' pointer, it should be NULL for static
4960 * methods, a MonoObject* for object instances and a pointer to
4961 * the value type for value types.
4963 * The params array contains the arguments to the method with the
4964 * same convention: MonoObject* pointers for object instances and
4965 * pointers to the value type otherwise. The _invoke_array
4966 * variant takes a C# object[] as the params argument (MonoArray
4967 * *params): in this case the value types are boxed inside the
4968 * respective reference representation.
4970 * From unmanaged code you'll usually use the
4971 * mono_runtime_invoke_checked() variant.
4973 * Note that this function doesn't handle virtual methods for
4974 * you, it will exec the exact method you pass: we still need to
4975 * expose a function to lookup the derived class implementation
4976 * of a virtual method (there are examples of this in the code,
4979 * On failure or exception, @error will be set. In that case, you
4980 * can't use the MonoObject* result from the function.
4982 * If the method returns a value type, it is boxed in an object
4986 mono_runtime_invoke_array_checked (MonoMethod *method, void *obj, MonoArray *params,
4990 return mono_runtime_try_invoke_array (method, obj, params, NULL, error);
4994 * mono_runtime_try_invoke_array:
4995 * @method: method to invoke
4996 * @obJ: object instance
4997 * @params: arguments to the method
4998 * @exc: exception information.
4999 * @error: set on failure.
5001 * Invokes the method represented by @method on the object @obj.
5003 * obj is the 'this' pointer, it should be NULL for static
5004 * methods, a MonoObject* for object instances and a pointer to
5005 * the value type for value types.
5007 * The params array contains the arguments to the method with the
5008 * same convention: MonoObject* pointers for object instances and
5009 * pointers to the value type otherwise. The _invoke_array
5010 * variant takes a C# object[] as the params argument (MonoArray
5011 * *params): in this case the value types are boxed inside the
5012 * respective reference representation.
5014 * From unmanaged code you'll usually use the
5015 * mono_runtime_invoke_checked() variant.
5017 * Note that this function doesn't handle virtual methods for
5018 * you, it will exec the exact method you pass: we still need to
5019 * expose a function to lookup the derived class implementation
5020 * of a virtual method (there are examples of this in the code,
5023 * You can pass NULL as the exc argument if you don't want to catch
5024 * exceptions, otherwise, *exc will be set to the exception thrown, if
5025 * any. On other failures, @error will be set. If an exception is
5026 * thrown or there's an error, you can't use the MonoObject* result
5027 * from the function.
5029 * If the method returns a value type, it is boxed in an object
5033 mono_runtime_try_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
5034 MonoObject **exc, MonoError *error)
5036 MONO_REQ_GC_UNSAFE_MODE;
5040 MonoMethodSignature *sig = mono_method_signature (method);
5041 gpointer *pa = NULL;
5044 gboolean has_byref_nullables = FALSE;
5046 if (NULL != params) {
5047 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
5048 for (i = 0; i < mono_array_length (params); i++) {
5049 MonoType *t = sig->params [i];
5050 pa [i] = invoke_array_extract_argument (params, i, t, &has_byref_nullables, error);
5051 return_val_if_nok (error, NULL);
5055 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
5058 if (mono_class_is_nullable (method->klass)) {
5059 /* Need to create a boxed vtype instead */
5065 return mono_value_box_checked (mono_domain_get (), method->klass->cast_class, pa [0], error);
5070 obj = mono_object_new_checked (mono_domain_get (), method->klass, error);
5071 mono_error_assert_ok (error);
5072 g_assert (obj); /*maybe we should raise a TLE instead?*/
5073 #ifndef DISABLE_REMOTING
5074 if (mono_object_is_transparent_proxy (obj)) {
5075 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
5078 if (method->klass->valuetype)
5079 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
5082 } else if (method->klass->valuetype) {
5083 obj = mono_value_box_checked (mono_domain_get (), method->klass, obj, error);
5084 return_val_if_nok (error, NULL);
5088 mono_runtime_try_invoke (method, o, pa, exc, error);
5090 mono_runtime_invoke_checked (method, o, pa, error);
5093 return (MonoObject *)obj;
5095 if (mono_class_is_nullable (method->klass)) {
5096 MonoObject *nullable;
5098 /* Convert the unboxed vtype into a Nullable structure */
5099 nullable = mono_object_new_checked (mono_domain_get (), method->klass, error);
5100 return_val_if_nok (error, NULL);
5102 MonoObject *boxed = mono_value_box_checked (mono_domain_get (), method->klass->cast_class, obj, error);
5103 return_val_if_nok (error, NULL);
5104 mono_nullable_init ((guint8 *)mono_object_unbox (nullable), boxed, method->klass);
5105 obj = mono_object_unbox (nullable);
5108 /* obj must be already unboxed if needed */
5110 res = mono_runtime_try_invoke (method, obj, pa, exc, error);
5112 res = mono_runtime_invoke_checked (method, obj, pa, error);
5114 return_val_if_nok (error, NULL);
5116 if (sig->ret->type == MONO_TYPE_PTR) {
5117 MonoClass *pointer_class;
5118 static MonoMethod *box_method;
5120 MonoObject *box_exc;
5123 * The runtime-invoke wrapper returns a boxed IntPtr, need to
5124 * convert it to a Pointer object.
5126 pointer_class = mono_class_get_pointer_class ();
5128 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
5130 g_assert (res->vtable->klass == mono_defaults.int_class);
5131 box_args [0] = ((MonoIntPtr*)res)->m_value;
5132 box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, error);
5133 return_val_if_nok (error, NULL);
5135 res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, error);
5136 g_assert (box_exc == NULL);
5137 mono_error_assert_ok (error);
5140 if (has_byref_nullables) {
5142 * The runtime invoke wrapper already converted byref nullables back,
5143 * and stored them in pa, we just need to copy them back to the
5146 for (i = 0; i < mono_array_length (params); i++) {
5147 MonoType *t = sig->params [i];
5149 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
5150 mono_array_setref (params, i, pa [i]);
5160 * @klass: the class of the object that we want to create
5162 * Returns: a newly created object whose definition is
5163 * looked up using @klass. This will not invoke any constructors,
5164 * so the consumer of this routine has to invoke any constructors on
5165 * its own to initialize the object.
5167 * It returns NULL on failure.
5170 mono_object_new (MonoDomain *domain, MonoClass *klass)
5172 MONO_REQ_GC_UNSAFE_MODE;
5176 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5178 mono_error_cleanup (&error);
5183 ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
5185 MONO_REQ_GC_UNSAFE_MODE;
5189 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5191 mono_error_set_pending_exception (&error);
5196 * mono_object_new_checked:
5197 * @klass: the class of the object that we want to create
5198 * @error: set on error
5200 * Returns: a newly created object whose definition is
5201 * looked up using @klass. This will not invoke any constructors,
5202 * so the consumer of this routine has to invoke any constructors on
5203 * its own to initialize the object.
5205 * It returns NULL on failure and sets @error.
5208 mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
5210 MONO_REQ_GC_UNSAFE_MODE;
5214 vtable = mono_class_vtable (domain, klass);
5215 g_assert (vtable); /* FIXME don't swallow the error */
5217 MonoObject *o = mono_object_new_specific_checked (vtable, error);
5222 * mono_object_new_pinned:
5224 * Same as mono_object_new, but the returned object will be pinned.
5225 * For SGEN, these objects will only be freed at appdomain unload.
5228 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
5230 MONO_REQ_GC_UNSAFE_MODE;
5236 vtable = mono_class_vtable (domain, klass);
5237 g_assert (vtable); /* FIXME don't swallow the error */
5239 MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
5241 if (G_UNLIKELY (!o))
5242 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
5243 else if (G_UNLIKELY (vtable->klass->has_finalize))
5244 mono_object_register_finalizer (o);
5250 * mono_object_new_specific:
5251 * @vtable: the vtable of the object that we want to create
5253 * Returns: A newly created object with class and domain specified
5257 mono_object_new_specific (MonoVTable *vtable)
5260 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5261 mono_error_cleanup (&error);
5267 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
5269 MONO_REQ_GC_UNSAFE_MODE;
5275 /* check for is_com_object for COM Interop */
5276 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
5279 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
5282 MonoClass *klass = mono_class_get_activation_services_class ();
5285 mono_class_init (klass);
5287 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
5289 mono_error_set_not_supported (error, "Linked away.");
5292 vtable->domain->create_proxy_for_type_method = im;
5295 pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
5296 if (!mono_error_ok (error))
5299 o = mono_runtime_invoke_checked (im, NULL, pa, error);
5300 if (!mono_error_ok (error))
5307 return mono_object_new_alloc_specific_checked (vtable, error);
5311 ves_icall_object_new_specific (MonoVTable *vtable)
5314 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5315 mono_error_set_pending_exception (&error);
5321 * mono_object_new_alloc_specific:
5322 * @vtable: virtual table for the object.
5324 * This function allocates a new `MonoObject` with the type derived
5325 * from the @vtable information. If the class of this object has a
5326 * finalizer, then the object will be tracked for finalization.
5328 * This method might raise an exception on errors. Use the
5329 * `mono_object_new_fast_checked` method if you want to manually raise
5332 * Returns: the allocated object.
5335 mono_object_new_alloc_specific (MonoVTable *vtable)
5338 MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
5339 mono_error_cleanup (&error);
5345 * mono_object_new_alloc_specific_checked:
5346 * @vtable: virtual table for the object.
5347 * @error: holds the error return value.
5349 * This function allocates a new `MonoObject` with the type derived
5350 * from the @vtable information. If the class of this object has a
5351 * finalizer, then the object will be tracked for finalization.
5353 * If there is not enough memory, the @error parameter will be set
5354 * and will contain a user-visible message with the amount of bytes
5355 * that were requested.
5357 * Returns: the allocated object, or NULL if there is not enough memory
5361 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
5363 MONO_REQ_GC_UNSAFE_MODE;
5369 o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5371 if (G_UNLIKELY (!o))
5372 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5373 else if (G_UNLIKELY (vtable->klass->has_finalize))
5374 mono_object_register_finalizer (o);
5380 * mono_object_new_fast:
5381 * @vtable: virtual table for the object.
5383 * This function allocates a new `MonoObject` with the type derived
5384 * from the @vtable information. The returned object is not tracked
5385 * for finalization. If your object implements a finalizer, you should
5386 * use `mono_object_new_alloc_specific` instead.
5388 * This method might raise an exception on errors. Use the
5389 * `mono_object_new_fast_checked` method if you want to manually raise
5392 * Returns: the allocated object.
5395 mono_object_new_fast (MonoVTable *vtable)
5398 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5399 mono_error_cleanup (&error);
5405 * mono_object_new_fast_checked:
5406 * @vtable: virtual table for the object.
5407 * @error: holds the error return value.
5409 * This function allocates a new `MonoObject` with the type derived
5410 * from the @vtable information. The returned object is not tracked
5411 * for finalization. If your object implements a finalizer, you should
5412 * use `mono_object_new_alloc_specific_checked` instead.
5414 * If there is not enough memory, the @error parameter will be set
5415 * and will contain a user-visible message with the amount of bytes
5416 * that were requested.
5418 * Returns: the allocated object, or NULL if there is not enough memory
5422 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
5424 MONO_REQ_GC_UNSAFE_MODE;
5430 o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5432 if (G_UNLIKELY (!o))
5433 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5439 ves_icall_object_new_fast (MonoVTable *vtable)
5442 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5443 mono_error_set_pending_exception (&error);
5449 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
5451 MONO_REQ_GC_UNSAFE_MODE;
5457 o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
5459 if (G_UNLIKELY (!o))
5460 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5461 else if (G_UNLIKELY (vtable->klass->has_finalize))
5462 mono_object_register_finalizer (o);
5468 * mono_class_get_allocation_ftn:
5470 * @for_box: the object will be used for boxing
5471 * @pass_size_in_words:
5473 * Return the allocation function appropriate for the given class.
5477 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
5479 MONO_REQ_GC_NEUTRAL_MODE;
5481 *pass_size_in_words = FALSE;
5483 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass))
5484 return ves_icall_object_new_specific;
5486 if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
5488 return ves_icall_object_new_fast;
5491 * FIXME: This is actually slower than ves_icall_object_new_fast, because
5492 * of the overhead of parameter passing.
5495 *pass_size_in_words = TRUE;
5496 #ifdef GC_REDIRECT_TO_LOCAL
5497 return GC_local_gcj_fast_malloc;
5499 return GC_gcj_fast_malloc;
5504 return ves_icall_object_new_specific;
5508 * mono_object_new_from_token:
5509 * @image: Context where the type_token is hosted
5510 * @token: a token of the type that we want to create
5512 * Returns: A newly created object whose definition is
5513 * looked up using @token in the @image image
5516 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
5518 MONO_REQ_GC_UNSAFE_MODE;
5524 klass = mono_class_get_checked (image, token, &error);
5525 mono_error_assert_ok (&error);
5527 result = mono_object_new_checked (domain, klass, &error);
5529 mono_error_cleanup (&error);
5536 * mono_object_clone:
5537 * @obj: the object to clone
5539 * Returns: A newly created object who is a shallow copy of @obj
5542 mono_object_clone (MonoObject *obj)
5545 MonoObject *o = mono_object_clone_checked (obj, &error);
5546 mono_error_cleanup (&error);
5552 mono_object_clone_checked (MonoObject *obj, MonoError *error)
5554 MONO_REQ_GC_UNSAFE_MODE;
5561 size = obj->vtable->klass->instance_size;
5563 if (obj->vtable->klass->rank)
5564 return (MonoObject*)mono_array_clone_checked ((MonoArray*)obj, error);
5566 o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
5568 if (G_UNLIKELY (!o)) {
5569 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5573 /* If the object doesn't contain references this will do a simple memmove. */
5574 mono_gc_wbarrier_object_copy (o, obj);
5576 if (obj->vtable->klass->has_finalize)
5577 mono_object_register_finalizer (o);
5582 * mono_array_full_copy:
5583 * @src: source array to copy
5584 * @dest: destination array
5586 * Copies the content of one array to another with exactly the same type and size.
5589 mono_array_full_copy (MonoArray *src, MonoArray *dest)
5591 MONO_REQ_GC_UNSAFE_MODE;
5594 MonoClass *klass = src->obj.vtable->klass;
5596 g_assert (klass == dest->obj.vtable->klass);
5598 size = mono_array_length (src);
5599 g_assert (size == mono_array_length (dest));
5600 size *= mono_array_element_size (klass);
5602 array_full_copy_unchecked_size (src, dest, klass, size);
5606 array_full_copy_unchecked_size (MonoArray *src, MonoArray *dest, MonoClass *klass, uintptr_t size)
5609 if (klass->element_class->valuetype) {
5610 if (klass->element_class->has_references)
5611 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
5613 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5615 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
5618 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5623 * mono_array_clone_in_domain:
5624 * @domain: the domain in which the array will be cloned into
5625 * @array: the array to clone
5626 * @error: set on error
5628 * This routine returns a copy of the array that is hosted on the
5629 * specified MonoDomain. On failure returns NULL and sets @error.
5632 mono_array_clone_in_domain (MonoDomain *domain, MonoArrayHandle array_handle, MonoError *error)
5634 MONO_REQ_GC_UNSAFE_MODE;
5636 MonoArrayHandle result = MONO_HANDLE_NEW (MonoArray, NULL);
5638 MonoClass *klass = mono_handle_class (array_handle);
5642 /* Pin source array here - if bounds is non-NULL, it's a pointer into the object data */
5643 uint32_t src_handle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, array_handle), TRUE);
5645 MonoArrayBounds *array_bounds = MONO_HANDLE_GETVAL (array_handle, bounds);
5647 if (array_bounds == NULL) {
5648 size = mono_array_handle_length (array_handle);
5649 o = mono_array_new_full_handle (domain, klass, &size, NULL, error);
5652 size *= mono_array_element_size (klass);
5654 uintptr_t *sizes = (uintptr_t *)alloca (klass->rank * sizeof (uintptr_t));
5655 intptr_t *lower_bounds = (intptr_t *)alloca (klass->rank * sizeof (intptr_t));
5656 size = mono_array_element_size (klass);
5657 for (int i = 0; i < klass->rank; ++i) {
5658 sizes [i] = array_bounds [i].length;
5659 size *= array_bounds [i].length;
5660 lower_bounds [i] = array_bounds [i].lower_bound;
5662 o = mono_array_new_full_handle (domain, klass, sizes, lower_bounds, error);
5667 uint32_t dst_handle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, o), TRUE);
5668 array_full_copy_unchecked_size (MONO_HANDLE_RAW (array_handle), MONO_HANDLE_RAW (o), klass, size);
5669 mono_gchandle_free (dst_handle);
5671 MONO_HANDLE_ASSIGN (result, o);
5674 mono_gchandle_free (src_handle);
5680 * @array: the array to clone
5682 * Returns: A newly created array who is a shallow copy of @array
5685 mono_array_clone (MonoArray *array)
5687 MONO_REQ_GC_UNSAFE_MODE;
5690 MonoArray *result = mono_array_clone_checked (array, &error);
5691 mono_error_cleanup (&error);
5696 * mono_array_clone_checked:
5697 * @array: the array to clone
5698 * @error: set on error
5700 * Returns: A newly created array who is a shallow copy of @array. On
5701 * failure returns NULL and sets @error.
5704 mono_array_clone_checked (MonoArray *array_raw, MonoError *error)
5706 MONO_REQ_GC_UNSAFE_MODE;
5707 HANDLE_FUNCTION_ENTER ();
5708 /* FIXME: callers of mono_array_clone_checked should use handles */
5710 MONO_HANDLE_DCL (MonoArray, array);
5711 MonoArrayHandle result = mono_array_clone_in_domain (MONO_HANDLE_DOMAIN (array), array, error);
5712 HANDLE_FUNCTION_RETURN_OBJ (result);
5715 /* helper macros to check for overflow when calculating the size of arrays */
5716 #ifdef MONO_BIG_ARRAYS
5717 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
5718 #define MYGUINT_MAX MYGUINT64_MAX
5719 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5720 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
5721 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5722 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
5723 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
5725 #define MYGUINT32_MAX 4294967295U
5726 #define MYGUINT_MAX MYGUINT32_MAX
5727 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5728 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
5729 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5730 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
5731 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
5735 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
5737 MONO_REQ_GC_NEUTRAL_MODE;
5741 byte_len = mono_array_element_size (klass);
5742 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
5745 if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
5747 byte_len += MONO_SIZEOF_MONO_ARRAY;
5755 * mono_array_new_full:
5756 * @domain: domain where the object is created
5757 * @array_class: array class
5758 * @lengths: lengths for each dimension in the array
5759 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
5761 * This routine creates a new array objects with the given dimensions,
5762 * lower bounds and type.
5765 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
5768 MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
5769 mono_error_cleanup (&error);
5775 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
5777 MONO_REQ_GC_UNSAFE_MODE;
5779 uintptr_t byte_len = 0, len, bounds_size;
5782 MonoArrayBounds *bounds;
5788 if (!array_class->inited)
5789 mono_class_init (array_class);
5793 /* A single dimensional array with a 0 lower bound is the same as an szarray */
5794 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
5796 if (len > MONO_ARRAY_MAX_INDEX) {
5797 mono_error_set_generic_error (error, "System", "OverflowException", "");
5802 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
5804 for (i = 0; i < array_class->rank; ++i) {
5805 if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
5806 mono_error_set_generic_error (error, "System", "OverflowException", "");
5809 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5810 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5817 if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5818 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5824 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5825 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5828 byte_len = (byte_len + 3) & ~3;
5829 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5830 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5833 byte_len += bounds_size;
5836 * Following three lines almost taken from mono_object_new ():
5837 * they need to be kept in sync.
5839 vtable = mono_class_vtable_full (domain, array_class, error);
5840 return_val_if_nok (error, NULL);
5843 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5845 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5847 if (G_UNLIKELY (!o)) {
5848 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5852 array = (MonoArray*)o;
5854 bounds = array->bounds;
5857 for (i = 0; i < array_class->rank; ++i) {
5858 bounds [i].length = lengths [i];
5860 bounds [i].lower_bound = lower_bounds [i];
5869 * @domain: domain where the object is created
5870 * @eclass: element class
5871 * @n: number of array elements
5873 * This routine creates a new szarray with @n elements of type @eclass.
5876 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5878 MONO_REQ_GC_UNSAFE_MODE;
5881 MonoArray *result = mono_array_new_checked (domain, eclass, n, &error);
5882 mono_error_cleanup (&error);
5887 * mono_array_new_checked:
5888 * @domain: domain where the object is created
5889 * @eclass: element class
5890 * @n: number of array elements
5891 * @error: set on error
5893 * This routine creates a new szarray with @n elements of type @eclass.
5894 * On failure returns NULL and sets @error.
5897 mono_array_new_checked (MonoDomain *domain, MonoClass *eclass, uintptr_t n, MonoError *error)
5903 ac = mono_array_class_get (eclass, 1);
5906 MonoVTable *vtable = mono_class_vtable_full (domain, ac, error);
5907 return_val_if_nok (error, NULL);
5909 return mono_array_new_specific_checked (vtable, n, error);
5913 ves_icall_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5916 MonoArray *arr = mono_array_new_checked (domain, eclass, n, &error);
5917 mono_error_set_pending_exception (&error);
5923 * mono_array_new_specific:
5924 * @vtable: a vtable in the appropriate domain for an initialized class
5925 * @n: number of array elements
5927 * This routine is a fast alternative to mono_array_new() for code which
5928 * can be sure about the domain it operates in.
5931 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5934 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5935 mono_error_cleanup (&error);
5941 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
5943 MONO_REQ_GC_UNSAFE_MODE;
5950 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
5951 mono_error_set_generic_error (error, "System", "OverflowException", "");
5955 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
5956 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5959 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
5961 if (G_UNLIKELY (!o)) {
5962 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5966 return (MonoArray*)o;
5970 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
5973 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5974 mono_error_set_pending_exception (&error);
5980 * mono_string_empty_wrapper:
5982 * Returns: The same empty string instance as the managed string.Empty
5985 mono_string_empty_wrapper (void)
5987 MonoDomain *domain = mono_domain_get ();
5988 return mono_string_empty (domain);
5992 * mono_string_empty:
5994 * Returns: The same empty string instance as the managed string.Empty
5997 mono_string_empty (MonoDomain *domain)
6000 g_assert (domain->empty_string);
6001 return domain->empty_string;
6005 * mono_string_new_utf16:
6006 * @text: a pointer to an utf16 string
6007 * @len: the length of the string
6009 * Returns: A newly created string object which contains @text.
6012 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
6014 MONO_REQ_GC_UNSAFE_MODE;
6017 MonoString *res = NULL;
6018 res = mono_string_new_utf16_checked (domain, text, len, &error);
6019 mono_error_cleanup (&error);
6025 * mono_string_new_utf16_checked:
6026 * @text: a pointer to an utf16 string
6027 * @len: the length of the string
6028 * @error: written on error.
6030 * Returns: A newly created string object which contains @text.
6031 * On error, returns NULL and sets @error.
6034 mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
6036 MONO_REQ_GC_UNSAFE_MODE;
6042 s = mono_string_new_size_checked (domain, len, error);
6044 memcpy (mono_string_chars (s), text, len * 2);
6050 * mono_string_new_utf16_handle:
6051 * @text: a pointer to an utf16 string
6052 * @len: the length of the string
6053 * @error: written on error.
6055 * Returns: A newly created string object which contains @text.
6056 * On error, returns NULL and sets @error.
6059 mono_string_new_utf16_handle (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
6061 return MONO_HANDLE_NEW (MonoString, mono_string_new_utf16_checked (domain, text, len, error));
6065 * mono_string_new_utf32:
6066 * @text: a pointer to an utf32 string
6067 * @len: the length of the string
6068 * @error: set on failure.
6070 * Returns: A newly created string object which contains @text. On failure returns NULL and sets @error.
6073 mono_string_new_utf32_checked (MonoDomain *domain, const mono_unichar4 *text, gint32 len, MonoError *error)
6075 MONO_REQ_GC_UNSAFE_MODE;
6078 mono_unichar2 *utf16_output = NULL;
6079 gint32 utf16_len = 0;
6080 GError *gerror = NULL;
6081 glong items_written;
6084 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
6087 g_error_free (gerror);
6089 while (utf16_output [utf16_len]) utf16_len++;
6091 s = mono_string_new_size_checked (domain, utf16_len, error);
6092 return_val_if_nok (error, NULL);
6094 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
6096 g_free (utf16_output);
6102 * mono_string_new_utf32:
6103 * @text: a pointer to an utf32 string
6104 * @len: the length of the string
6106 * Returns: A newly created string object which contains @text.
6109 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
6112 MonoString *result = mono_string_new_utf32_checked (domain, text, len, &error);
6113 mono_error_cleanup (&error);
6118 * mono_string_new_size:
6119 * @text: a pointer to an utf16 string
6120 * @len: the length of the string
6122 * Returns: A newly created string object of @len
6125 mono_string_new_size (MonoDomain *domain, gint32 len)
6128 MonoString *str = mono_string_new_size_checked (domain, len, &error);
6129 mono_error_cleanup (&error);
6135 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
6137 MONO_REQ_GC_UNSAFE_MODE;
6145 /* check for overflow */
6146 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
6147 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
6151 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
6152 g_assert (size > 0);
6154 vtable = mono_class_vtable (domain, mono_defaults.string_class);
6157 s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
6159 if (G_UNLIKELY (!s)) {
6160 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", size);
6168 * mono_string_new_len:
6169 * @text: a pointer to an utf8 string
6170 * @length: number of bytes in @text to consider
6172 * Returns: A newly created string object which contains @text.
6175 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
6177 MONO_REQ_GC_UNSAFE_MODE;
6180 MonoString *result = mono_string_new_len_checked (domain, text, length, &error);
6181 mono_error_cleanup (&error);
6186 * mono_string_new_len_checked:
6187 * @text: a pointer to an utf8 string
6188 * @length: number of bytes in @text to consider
6189 * @error: set on error
6191 * Returns: A newly created string object which contains @text. On
6192 * failure returns NULL and sets @error.
6195 mono_string_new_len_checked (MonoDomain *domain, const char *text, guint length, MonoError *error)
6197 MONO_REQ_GC_UNSAFE_MODE;
6201 GError *eg_error = NULL;
6202 MonoString *o = NULL;
6204 glong items_written;
6206 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
6209 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6211 g_error_free (eg_error);
6220 * @text: a pointer to an utf8 string
6222 * Returns: A newly created string object which contains @text.
6224 * This function asserts if it cannot allocate a new string.
6226 * @deprecated Use mono_string_new_checked in new code.
6229 mono_string_new (MonoDomain *domain, const char *text)
6232 MonoString *res = NULL;
6233 res = mono_string_new_checked (domain, text, &error);
6234 mono_error_assert_ok (&error);
6239 * mono_string_new_checked:
6240 * @text: a pointer to an utf8 string
6241 * @merror: set on error
6243 * Returns: A newly created string object which contains @text.
6244 * On error returns NULL and sets @merror.
6247 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
6249 MONO_REQ_GC_UNSAFE_MODE;
6251 GError *eg_error = NULL;
6252 MonoString *o = NULL;
6254 glong items_written;
6261 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &eg_error);
6264 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6266 g_error_free (eg_error);
6270 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
6275 MonoString *o = NULL;
6277 if (!g_utf8_validate (text, -1, &end)) {
6278 mono_error_set_argument (error, "text", "Not a valid utf8 string");
6282 len = g_utf8_strlen (text, -1);
6283 o = mono_string_new_size_checked (domain, len, error);
6286 str = mono_string_chars (o);
6288 while (text < end) {
6289 *str++ = g_utf8_get_char (text);
6290 text = g_utf8_next_char (text);
6299 * mono_string_new_wrapper:
6300 * @text: pointer to utf8 characters.
6302 * Helper function to create a string object from @text in the current domain.
6305 mono_string_new_wrapper (const char *text)
6307 MONO_REQ_GC_UNSAFE_MODE;
6309 MonoDomain *domain = mono_domain_get ();
6312 return mono_string_new (domain, text);
6319 * @class: the class of the value
6320 * @value: a pointer to the unboxed data
6322 * Returns: A newly created object which contains @value.
6325 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
6328 MonoObject *result = mono_value_box_checked (domain, klass, value, &error);
6329 mono_error_cleanup (&error);
6334 * mono_value_box_checked:
6335 * @domain: the domain of the new object
6336 * @class: the class of the value
6337 * @value: a pointer to the unboxed data
6338 * @error: set on error
6340 * Returns: A newly created object which contains @value. On failure
6341 * returns NULL and sets @error.
6344 mono_value_box_checked (MonoDomain *domain, MonoClass *klass, gpointer value, MonoError *error)
6346 MONO_REQ_GC_UNSAFE_MODE;
6353 g_assert (klass->valuetype);
6354 if (mono_class_is_nullable (klass))
6355 return mono_nullable_box ((guint8 *)value, klass, error);
6357 vtable = mono_class_vtable (domain, klass);
6360 size = mono_class_instance_size (klass);
6361 res = mono_object_new_alloc_specific_checked (vtable, error);
6362 return_val_if_nok (error, NULL);
6364 size = size - sizeof (MonoObject);
6367 g_assert (size == mono_class_value_size (klass, NULL));
6368 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
6370 #if NO_UNALIGNED_ACCESS
6371 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6375 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
6378 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
6381 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
6384 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
6387 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6391 if (klass->has_finalize) {
6392 mono_object_register_finalizer (res);
6393 return_val_if_nok (error, NULL);
6400 * @dest: destination pointer
6401 * @src: source pointer
6402 * @klass: a valuetype class
6404 * Copy a valuetype from @src to @dest. This function must be used
6405 * when @klass contains references fields.
6408 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
6410 MONO_REQ_GC_UNSAFE_MODE;
6412 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
6416 * mono_value_copy_array:
6417 * @dest: destination array
6418 * @dest_idx: index in the @dest array
6419 * @src: source pointer
6420 * @count: number of items
6422 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
6423 * This function must be used when @klass contains references fields.
6424 * Overlap is handled.
6427 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
6429 MONO_REQ_GC_UNSAFE_MODE;
6431 int size = mono_array_element_size (dest->obj.vtable->klass);
6432 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
6433 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
6434 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
6438 * mono_object_get_domain:
6439 * @obj: object to query
6441 * Returns: the MonoDomain where the object is hosted
6444 mono_object_get_domain (MonoObject *obj)
6446 MONO_REQ_GC_UNSAFE_MODE;
6448 return mono_object_domain (obj);
6452 * mono_object_get_class:
6453 * @obj: object to query
6455 * Use this function to obtain the `MonoClass*` for a given `MonoObject`.
6457 * Returns: the MonoClass of the object.
6460 mono_object_get_class (MonoObject *obj)
6462 MONO_REQ_GC_UNSAFE_MODE;
6464 return mono_object_class (obj);
6467 * mono_object_get_size:
6468 * @o: object to query
6470 * Returns: the size, in bytes, of @o
6473 mono_object_get_size (MonoObject* o)
6475 MONO_REQ_GC_UNSAFE_MODE;
6477 MonoClass* klass = mono_object_class (o);
6478 if (klass == mono_defaults.string_class) {
6479 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
6480 } else if (o->vtable->rank) {
6481 MonoArray *array = (MonoArray*)o;
6482 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
6483 if (array->bounds) {
6486 size += sizeof (MonoArrayBounds) * o->vtable->rank;
6490 return mono_class_instance_size (klass);
6495 * mono_object_unbox:
6496 * @obj: object to unbox
6498 * Returns: a pointer to the start of the valuetype boxed in this
6501 * This method will assert if the object passed is not a valuetype.
6504 mono_object_unbox (MonoObject *obj)
6506 MONO_REQ_GC_UNSAFE_MODE;
6508 /* add assert for valuetypes? */
6509 g_assert (obj->vtable->klass->valuetype);
6510 return ((char*)obj) + sizeof (MonoObject);
6514 * mono_object_isinst:
6516 * @klass: a pointer to a class
6518 * Returns: @obj if @obj is derived from @klass or NULL otherwise.
6521 mono_object_isinst (MonoObject *obj_raw, MonoClass *klass)
6523 MONO_REQ_GC_UNSAFE_MODE;
6525 HANDLE_FUNCTION_ENTER ();
6526 MONO_HANDLE_DCL (MonoObject, obj);
6528 MonoObjectHandle result = mono_object_handle_isinst (obj, klass, &error);
6529 mono_error_cleanup (&error);
6530 HANDLE_FUNCTION_RETURN_OBJ (result);
6535 * mono_object_isinst_checked:
6537 * @klass: a pointer to a class
6538 * @error: set on error
6540 * Returns: @obj if @obj is derived from @klass or NULL if it isn't.
6541 * On failure returns NULL and sets @error.
6544 mono_object_isinst_checked (MonoObject *obj_raw, MonoClass *klass, MonoError *error)
6546 MONO_REQ_GC_UNSAFE_MODE;
6548 HANDLE_FUNCTION_ENTER ();
6550 MONO_HANDLE_DCL (MonoObject, obj);
6551 MonoObjectHandle result = mono_object_handle_isinst (obj, klass, error);
6552 HANDLE_FUNCTION_RETURN_OBJ (result);
6556 * mono_object_handle_isinst:
6558 * @klass: a pointer to a class
6559 * @error: set on error
6561 * Returns: @obj if @obj is derived from @klass or NULL if it isn't.
6562 * On failure returns NULL and sets @error.
6565 mono_object_handle_isinst (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
6570 mono_class_init (klass);
6572 if (mono_class_is_marshalbyref (klass) || mono_class_is_interface (klass)) {
6573 return mono_object_handle_isinst_mbyref (obj, klass, error);
6576 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6578 if (!MONO_HANDLE_IS_NULL (obj) && mono_class_is_assignable_from (klass, mono_handle_class (obj)))
6579 MONO_HANDLE_ASSIGN (result, obj);
6584 mono_object_isinst_mbyref (MonoObject *obj_raw, MonoClass *klass)
6586 MONO_REQ_GC_UNSAFE_MODE;
6588 HANDLE_FUNCTION_ENTER ();
6590 MONO_HANDLE_DCL (MonoObject, obj);
6591 MonoObjectHandle result = mono_object_handle_isinst_mbyref (obj, klass, &error);
6592 mono_error_cleanup (&error); /* FIXME better API that doesn't swallow the error */
6593 HANDLE_FUNCTION_RETURN_OBJ (result);
6597 mono_object_handle_isinst_mbyref (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
6601 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6603 if (MONO_HANDLE_IS_NULL (obj))
6606 MonoVTable *vt = MONO_HANDLE_GETVAL (obj, vtable);
6608 if (mono_class_is_interface (klass)) {
6609 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
6610 MONO_HANDLE_ASSIGN (result, obj);
6614 /* casting an array one of the invariant interfaces that must act as such */
6615 if (klass->is_array_special_interface) {
6616 if (mono_class_is_assignable_from (klass, vt->klass)) {
6617 MONO_HANDLE_ASSIGN (result, obj);
6622 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
6623 else if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, mono_handle_class (obj))) {
6624 MONO_HANDLE_ASSIGN (result, obj);
6628 MonoClass *oklass = vt->klass;
6629 if (mono_class_is_transparent_proxy (oklass)){
6630 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), remote_class);
6631 oklass = remote_class->proxy_class;
6634 mono_class_setup_supertypes (klass);
6635 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass)) {
6636 MONO_HANDLE_ASSIGN (result, obj);
6640 #ifndef DISABLE_REMOTING
6641 if (mono_class_is_transparent_proxy (vt->klass))
6643 MonoBoolean custom_type_info = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), custom_type_info);
6644 if (!custom_type_info)
6646 MonoDomain *domain = mono_domain_get ();
6647 MonoObjectHandle rp = MONO_HANDLE_NEW (MonoObject, NULL);
6648 MONO_HANDLE_GET (rp, MONO_HANDLE_CAST (MonoTransparentProxy, obj), rp);
6649 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
6650 MonoMethod *im = NULL;
6653 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
6655 mono_error_set_not_supported (error, "Linked away.");
6658 im = mono_object_handle_get_virtual_method (rp, im, error);
6663 MonoReflectionTypeHandle reftype = mono_type_get_object_handle (domain, &klass->byval_arg, error);
6667 pa [0] = MONO_HANDLE_RAW (reftype);
6668 pa [1] = MONO_HANDLE_RAW (obj);
6669 MonoObject *res = mono_runtime_invoke_checked (im, rp, pa, error);
6673 if (*(MonoBoolean *) mono_object_unbox(res)) {
6674 /* Update the vtable of the remote type, so it can safely cast to this new type */
6675 mono_upgrade_remote_class (domain, obj, klass, error);
6678 MONO_HANDLE_ASSIGN (result, obj);
6681 #endif /* DISABLE_REMOTING */
6687 * mono_object_castclass_mbyref:
6689 * @klass: a pointer to a class
6691 * Returns: @obj if @obj is derived from @klass, returns NULL otherwise.
6694 mono_object_castclass_mbyref (MonoObject *obj_raw, MonoClass *klass)
6696 MONO_REQ_GC_UNSAFE_MODE;
6697 HANDLE_FUNCTION_ENTER ();
6699 MONO_HANDLE_DCL (MonoObject, obj);
6700 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6701 if (MONO_HANDLE_IS_NULL (obj))
6703 MONO_HANDLE_ASSIGN (result, mono_object_handle_isinst_mbyref (obj, klass, &error));
6704 mono_error_cleanup (&error);
6706 HANDLE_FUNCTION_RETURN_OBJ (result);
6710 MonoDomain *orig_domain;
6716 str_lookup (MonoDomain *domain, gpointer user_data)
6718 MONO_REQ_GC_UNSAFE_MODE;
6720 LDStrInfo *info = (LDStrInfo *)user_data;
6721 if (info->res || domain == info->orig_domain)
6723 info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
6727 mono_string_get_pinned (MonoString *str, MonoError *error)
6729 MONO_REQ_GC_UNSAFE_MODE;
6733 /* We only need to make a pinned version of a string if this is a moving GC */
6734 if (!mono_gc_is_moving ())
6738 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
6739 news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
6741 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
6742 news->length = mono_string_length (str);
6744 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6750 mono_string_is_interned_lookup (MonoString *str, int insert, MonoError *error)
6752 MONO_REQ_GC_UNSAFE_MODE;
6754 MonoGHashTable *ldstr_table;
6755 MonoString *s, *res;
6760 domain = ((MonoObject *)str)->vtable->domain;
6761 ldstr_table = domain->ldstr_table;
6763 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6769 /* Allocate outside the lock */
6771 s = mono_string_get_pinned (str, error);
6772 return_val_if_nok (error, NULL);
6775 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6780 mono_g_hash_table_insert (ldstr_table, s, s);
6785 LDStrInfo ldstr_info;
6786 ldstr_info.orig_domain = domain;
6787 ldstr_info.ins = str;
6788 ldstr_info.res = NULL;
6790 mono_domain_foreach (str_lookup, &ldstr_info);
6791 if (ldstr_info.res) {
6793 * the string was already interned in some other domain:
6794 * intern it in the current one as well.
6796 mono_g_hash_table_insert (ldstr_table, str, str);
6806 * mono_string_is_interned:
6807 * @o: String to probe
6809 * Returns whether the string has been interned.
6812 mono_string_is_interned (MonoString *o)
6815 MonoString *result = mono_string_is_interned_lookup (o, FALSE, &error);
6816 /* This function does not fail. */
6817 mono_error_assert_ok (&error);
6822 * mono_string_intern:
6823 * @o: String to intern
6825 * Interns the string passed.
6826 * Returns: The interned string.
6829 mono_string_intern (MonoString *str)
6832 MonoString *result = mono_string_intern_checked (str, &error);
6833 mono_error_assert_ok (&error);
6838 * mono_string_intern_checked:
6839 * @o: String to intern
6840 * @error: set on error.
6842 * Interns the string passed.
6843 * Returns: The interned string. On failure returns NULL and sets @error
6846 mono_string_intern_checked (MonoString *str, MonoError *error)
6848 MONO_REQ_GC_UNSAFE_MODE;
6852 return mono_string_is_interned_lookup (str, TRUE, error);
6857 * @domain: the domain where the string will be used.
6858 * @image: a metadata context
6859 * @idx: index into the user string table.
6861 * Implementation for the ldstr opcode.
6862 * Returns: a loaded string from the @image/@idx combination.
6865 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
6868 MonoString *result = mono_ldstr_checked (domain, image, idx, &error);
6869 mono_error_cleanup (&error);
6874 * mono_ldstr_checked:
6875 * @domain: the domain where the string will be used.
6876 * @image: a metadata context
6877 * @idx: index into the user string table.
6878 * @error: set on error.
6880 * Implementation for the ldstr opcode.
6881 * Returns: a loaded string from the @image/@idx combination.
6882 * On failure returns NULL and sets @error.
6885 mono_ldstr_checked (MonoDomain *domain, MonoImage *image, guint32 idx, MonoError *error)
6887 MONO_REQ_GC_UNSAFE_MODE;
6890 if (image->dynamic) {
6891 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL, error);
6894 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6895 return NULL; /*FIXME we should probably be raising an exception here*/
6896 MonoString *str = mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx), error);
6902 * mono_ldstr_metadata_sig
6903 * @domain: the domain for the string
6904 * @sig: the signature of a metadata string
6905 * @error: set on error
6907 * Returns: a MonoString for a string stored in the metadata. On
6908 * failure returns NULL and sets @error.
6911 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error)
6913 MONO_REQ_GC_UNSAFE_MODE;
6916 const char *str = sig;
6917 MonoString *o, *interned;
6920 len2 = mono_metadata_decode_blob_size (str, &str);
6923 o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, error);
6924 return_val_if_nok (error, NULL);
6925 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
6928 guint16 *p2 = (guint16*)mono_string_chars (o);
6929 for (i = 0; i < len2; ++i) {
6930 *p2 = GUINT16_FROM_LE (*p2);
6936 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6939 return interned; /* o will get garbage collected */
6941 o = mono_string_get_pinned (o, error);
6944 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6946 mono_g_hash_table_insert (domain->ldstr_table, o, o);
6958 * Same as mono_ldstr, but return a NULL terminated utf8 string instead
6962 mono_ldstr_utf8 (MonoImage *image, guint32 idx, MonoError *error)
6968 GError *gerror = NULL;
6972 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6973 return NULL; /*FIXME we should probably be raising an exception here*/
6974 str = mono_metadata_user_string (image, idx);
6976 len2 = mono_metadata_decode_blob_size (str, &str);
6979 as = g_utf16_to_utf8 ((guint16*)str, len2, NULL, &written, &gerror);
6981 mono_error_set_argument (error, "string", "%s", gerror->message);
6982 g_error_free (gerror);
6985 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6986 if (len2 > written) {
6987 /* allocate the total length and copy the part of the string that has been converted */
6988 char *as2 = (char *)g_malloc0 (len2);
6989 memcpy (as2, as, written);
6998 * mono_string_to_utf8:
6999 * @s: a System.String
7001 * Returns the UTF8 representation for @s.
7002 * The resulting buffer needs to be freed with mono_free().
7004 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
7007 mono_string_to_utf8 (MonoString *s)
7009 MONO_REQ_GC_UNSAFE_MODE;
7012 char *result = mono_string_to_utf8_checked (s, &error);
7014 if (!is_ok (&error)) {
7015 mono_error_cleanup (&error);
7022 * mono_string_to_utf8_checked:
7023 * @s: a System.String
7024 * @error: a MonoError.
7026 * Converts a MonoString to its UTF8 representation. May fail; check
7027 * @error to determine whether the conversion was successful.
7028 * The resulting buffer should be freed with mono_free().
7031 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
7033 MONO_REQ_GC_UNSAFE_MODE;
7037 GError *gerror = NULL;
7045 return g_strdup ("");
7047 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
7049 mono_error_set_argument (error, "string", "%s", gerror->message);
7050 g_error_free (gerror);
7053 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
7054 if (s->length > written) {
7055 /* allocate the total length and copy the part of the string that has been converted */
7056 char *as2 = (char *)g_malloc0 (s->length);
7057 memcpy (as2, as, written);
7066 mono_string_handle_to_utf8 (MonoStringHandle s, MonoError *error)
7068 return mono_string_to_utf8_checked (MONO_HANDLE_RAW (s), error);
7072 * mono_string_to_utf8_ignore:
7075 * Converts a MonoString to its UTF8 representation. Will ignore
7076 * invalid surrogate pairs.
7077 * The resulting buffer should be freed with mono_free().
7081 mono_string_to_utf8_ignore (MonoString *s)
7083 MONO_REQ_GC_UNSAFE_MODE;
7092 return g_strdup ("");
7094 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
7096 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
7097 if (s->length > written) {
7098 /* allocate the total length and copy the part of the string that has been converted */
7099 char *as2 = (char *)g_malloc0 (s->length);
7100 memcpy (as2, as, written);
7109 * mono_string_to_utf8_image_ignore:
7110 * @s: a System.String
7112 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
7115 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
7117 MONO_REQ_GC_UNSAFE_MODE;
7119 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
7123 * mono_string_to_utf8_mp_ignore:
7124 * @s: a System.String
7126 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
7129 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
7131 MONO_REQ_GC_UNSAFE_MODE;
7133 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
7138 * mono_string_to_utf16:
7141 * Return an null-terminated array of the utf-16 chars
7142 * contained in @s. The result must be freed with g_free().
7143 * This is a temporary helper until our string implementation
7144 * is reworked to always include the null terminating char.
7147 mono_string_to_utf16 (MonoString *s)
7149 MONO_REQ_GC_UNSAFE_MODE;
7156 as = (char *)g_malloc ((s->length * 2) + 2);
7157 as [(s->length * 2)] = '\0';
7158 as [(s->length * 2) + 1] = '\0';
7161 return (gunichar2 *)(as);
7164 memcpy (as, mono_string_chars(s), s->length * 2);
7165 return (gunichar2 *)(as);
7169 * mono_string_to_utf32:
7172 * Return an null-terminated array of the UTF-32 (UCS-4) chars
7173 * contained in @s. The result must be freed with g_free().
7176 mono_string_to_utf32 (MonoString *s)
7178 MONO_REQ_GC_UNSAFE_MODE;
7180 mono_unichar4 *utf32_output = NULL;
7181 GError *error = NULL;
7182 glong items_written;
7187 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
7190 g_error_free (error);
7192 return utf32_output;
7196 * mono_string_from_utf16:
7197 * @data: the UTF16 string (LPWSTR) to convert
7199 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
7201 * Returns: a MonoString.
7204 mono_string_from_utf16 (gunichar2 *data)
7207 MonoString *result = mono_string_from_utf16_checked (data, &error);
7208 mono_error_cleanup (&error);
7213 * mono_string_from_utf16_checked:
7214 * @data: the UTF16 string (LPWSTR) to convert
7215 * @error: set on error
7217 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
7219 * Returns: a MonoString. On failure sets @error and returns NULL.
7222 mono_string_from_utf16_checked (gunichar2 *data, MonoError *error)
7225 MONO_REQ_GC_UNSAFE_MODE;
7228 MonoDomain *domain = mono_domain_get ();
7234 while (data [len]) len++;
7236 return mono_string_new_utf16_checked (domain, data, len, error);
7240 * mono_string_from_utf32:
7241 * @data: the UTF32 string (LPWSTR) to convert
7243 * Converts a UTF32 (UCS-4)to a MonoString.
7245 * Returns: a MonoString.
7248 mono_string_from_utf32 (mono_unichar4 *data)
7251 MonoString *result = mono_string_from_utf32_checked (data, &error);
7252 mono_error_cleanup (&error);
7257 * mono_string_from_utf32_checked:
7258 * @data: the UTF32 string (LPWSTR) to convert
7259 * @error: set on error
7261 * Converts a UTF32 (UCS-4)to a MonoString.
7263 * Returns: a MonoString. On failure returns NULL and sets @error.
7266 mono_string_from_utf32_checked (mono_unichar4 *data, MonoError *error)
7268 MONO_REQ_GC_UNSAFE_MODE;
7271 MonoString* result = NULL;
7272 mono_unichar2 *utf16_output = NULL;
7273 GError *gerror = NULL;
7274 glong items_written;
7280 while (data [len]) len++;
7282 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &gerror);
7285 g_error_free (gerror);
7287 result = mono_string_from_utf16_checked (utf16_output, error);
7288 g_free (utf16_output);
7293 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
7295 MONO_REQ_GC_UNSAFE_MODE;
7302 r = mono_string_to_utf8_ignore (s);
7304 r = mono_string_to_utf8_checked (s, error);
7305 if (!mono_error_ok (error))
7312 len = strlen (r) + 1;
7314 mp_s = (char *)mono_mempool_alloc (mp, len);
7316 mp_s = (char *)mono_image_alloc (image, len);
7318 memcpy (mp_s, r, len);
7326 * mono_string_to_utf8_image:
7327 * @s: a System.String
7329 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
7332 mono_string_to_utf8_image (MonoImage *image, MonoStringHandle s, MonoError *error)
7334 MONO_REQ_GC_UNSAFE_MODE;
7336 return mono_string_to_utf8_internal (NULL, image, MONO_HANDLE_RAW (s), FALSE, error); /* FIXME pin the string */
7340 * mono_string_to_utf8_mp:
7341 * @s: a System.String
7343 * Same as mono_string_to_utf8, but allocate the string from a mempool.
7346 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
7348 MONO_REQ_GC_UNSAFE_MODE;
7350 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
7354 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
7357 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
7359 eh_callbacks = *cbs;
7362 MonoRuntimeExceptionHandlingCallbacks *
7363 mono_get_eh_callbacks (void)
7365 return &eh_callbacks;
7369 * mono_raise_exception:
7370 * @ex: exception object
7372 * Signal the runtime that the exception @ex has been raised in unmanaged code.
7375 mono_raise_exception (MonoException *ex)
7377 MONO_REQ_GC_UNSAFE_MODE;
7380 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
7381 * that will cause gcc to omit the function epilog, causing problems when
7382 * the JIT tries to walk the stack, since the return address on the stack
7383 * will point into the next function in the executable, not this one.
7385 eh_callbacks.mono_raise_exception (ex);
7389 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
7391 MONO_REQ_GC_UNSAFE_MODE;
7393 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
7397 * mono_wait_handle_new:
7398 * @domain: Domain where the object will be created
7399 * @handle: Handle for the wait handle
7400 * @error: set on error.
7402 * Returns: A new MonoWaitHandle created in the given domain for the
7403 * given handle. On failure returns NULL and sets @rror.
7406 mono_wait_handle_new (MonoDomain *domain, HANDLE handle, MonoError *error)
7408 MONO_REQ_GC_UNSAFE_MODE;
7410 MonoWaitHandle *res;
7411 gpointer params [1];
7412 static MonoMethod *handle_set;
7415 res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, error);
7416 return_val_if_nok (error, NULL);
7418 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
7420 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
7422 params [0] = &handle;
7424 mono_runtime_invoke_checked (handle_set, res, params, error);
7429 mono_wait_handle_get_handle (MonoWaitHandle *handle)
7431 MONO_REQ_GC_UNSAFE_MODE;
7433 static MonoClassField *f_safe_handle = NULL;
7436 if (!f_safe_handle) {
7437 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safeWaitHandle");
7438 g_assert (f_safe_handle);
7441 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
7447 mono_runtime_capture_context (MonoDomain *domain, MonoError *error)
7449 MONO_REQ_GC_UNSAFE_MODE;
7451 RuntimeInvokeFunction runtime_invoke;
7455 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
7456 MonoMethod *method = mono_get_context_capture_method ();
7457 MonoMethod *wrapper;
7460 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
7461 domain->capture_context_runtime_invoke = mono_compile_method_checked (wrapper, error);
7462 return_val_if_nok (error, NULL);
7463 domain->capture_context_method = mono_compile_method_checked (method, error);
7464 return_val_if_nok (error, NULL);
7467 runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
7469 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
7472 * mono_async_result_new:
7473 * @domain:domain where the object will be created.
7474 * @handle: wait handle.
7475 * @state: state to pass to AsyncResult
7476 * @data: C closure data.
7477 * @error: set on error.
7479 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
7480 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
7481 * On failure returns NULL and sets @error.
7485 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data, MonoError *error)
7487 MONO_REQ_GC_UNSAFE_MODE;
7490 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, error);
7491 return_val_if_nok (error, NULL);
7492 MonoObject *context = mono_runtime_capture_context (domain, error);
7493 return_val_if_nok (error, NULL);
7494 /* we must capture the execution context from the original thread */
7496 MONO_OBJECT_SETREF (res, execution_context, context);
7497 /* note: result may be null if the flow is suppressed */
7500 res->data = (void **)data;
7501 MONO_OBJECT_SETREF (res, object_data, object_data);
7502 MONO_OBJECT_SETREF (res, async_state, state);
7503 MonoWaitHandle *wait_handle = mono_wait_handle_new (domain, handle, error);
7504 return_val_if_nok (error, NULL);
7506 MONO_OBJECT_SETREF (res, handle, (MonoObject *) wait_handle);
7508 res->sync_completed = FALSE;
7509 res->completed = FALSE;
7515 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
7517 MONO_REQ_GC_UNSAFE_MODE;
7524 g_assert (ares->async_delegate);
7526 ac = (MonoAsyncCall*) ares->object_data;
7528 res = mono_runtime_delegate_invoke_checked (ares->async_delegate, (void**) &ares->async_state, &error);
7529 if (mono_error_set_pending_exception (&error))
7532 gpointer wait_event = NULL;
7534 ac->msg->exc = NULL;
7536 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args, &error);
7538 /* The exit side of the invoke must not be aborted as it would leave the runtime in an undefined state */
7539 mono_threads_begin_abort_protected_block ();
7541 if (!ac->msg->exc) {
7542 MonoException *ex = mono_error_convert_to_exception (&error);
7543 ac->msg->exc = (MonoObject *)ex;
7545 mono_error_cleanup (&error);
7548 MONO_OBJECT_SETREF (ac, res, res);
7550 mono_monitor_enter ((MonoObject*) ares);
7551 ares->completed = 1;
7553 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
7554 mono_monitor_exit ((MonoObject*) ares);
7556 if (wait_event != NULL)
7557 mono_w32event_set (wait_event);
7559 error_init (&error); //the else branch would leave it in an undefined state
7561 mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
7563 mono_threads_end_abort_protected_block ();
7565 if (mono_error_set_pending_exception (&error))
7573 mono_message_init (MonoDomain *domain,
7574 MonoMethodMessage *this_obj,
7575 MonoReflectionMethod *method,
7576 MonoArray *out_args,
7579 MONO_REQ_GC_UNSAFE_MODE;
7581 static MonoMethod *init_message_method = NULL;
7583 if (!init_message_method) {
7584 init_message_method = mono_class_get_method_from_name (mono_defaults.mono_method_message_class, "InitMessage", 2);
7585 g_assert (init_message_method != NULL);
7589 /* FIXME set domain instead? */
7590 g_assert (domain == mono_domain_get ());
7597 mono_runtime_invoke_checked (init_message_method, this_obj, args, error);
7598 return is_ok (error);
7601 #ifndef DISABLE_REMOTING
7603 * mono_remoting_invoke:
7604 * @real_proxy: pointer to a RealProxy object
7605 * @msg: The MonoMethodMessage to execute
7606 * @exc: used to store exceptions
7607 * @out_args: used to store output arguments
7609 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
7610 * IMessage interface and it is not trivial to extract results from there. So
7611 * we call an helper method PrivateInvoke instead of calling
7612 * RealProxy::Invoke() directly.
7614 * Returns: the result object.
7617 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, MonoObject **exc, MonoArray **out_args, MonoError *error)
7619 MONO_REQ_GC_UNSAFE_MODE;
7622 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
7629 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
7632 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
7634 mono_error_set_not_supported (error, "Linked away.");
7637 real_proxy->vtable->domain->private_invoke_method = im;
7640 pa [0] = real_proxy;
7645 o = mono_runtime_try_invoke (im, NULL, pa, exc, error);
7646 return_val_if_nok (error, NULL);
7653 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
7654 MonoObject **exc, MonoArray **out_args, MonoError *error)
7656 MONO_REQ_GC_UNSAFE_MODE;
7658 static MonoClass *object_array_klass;
7663 MonoMethodSignature *sig;
7665 int i, j, outarg_count = 0;
7667 #ifndef DISABLE_REMOTING
7668 if (target && mono_object_is_transparent_proxy (target)) {
7669 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
7670 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7671 target = tp->rp->unwrapped_server;
7673 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args, error);
7678 domain = mono_domain_get ();
7679 method = msg->method->method;
7680 sig = mono_method_signature (method);
7682 for (i = 0; i < sig->param_count; i++) {
7683 if (sig->params [i]->byref)
7687 if (!object_array_klass) {
7690 klass = mono_array_class_get (mono_defaults.object_class, 1);
7693 mono_memory_barrier ();
7694 object_array_klass = klass;
7697 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, error);
7698 return_val_if_nok (error, NULL);
7700 mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
7703 MonoObject *ret = mono_runtime_try_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc, error);
7704 return_val_if_nok (error, NULL);
7706 for (i = 0, j = 0; i < sig->param_count; i++) {
7707 if (sig->params [i]->byref) {
7709 arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
7710 mono_array_setref (*out_args, j, arg);
7719 * prepare_to_string_method:
7721 * @target: Set to @obj or unboxed value if a valuetype
7723 * Returns: the ToString override for @obj. If @obj is a valuetype, @target is unboxed otherwise it's @obj.
7726 prepare_to_string_method (MonoObject *obj, void **target)
7728 MONO_REQ_GC_UNSAFE_MODE;
7730 static MonoMethod *to_string = NULL;
7738 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
7740 method = mono_object_get_virtual_method (obj, to_string);
7742 // Unbox value type if needed
7743 if (mono_class_is_valuetype (mono_method_get_class (method))) {
7744 *target = mono_object_unbox (obj);
7750 * mono_object_to_string:
7752 * @exc: Any exception thrown by ToString (). May be NULL.
7754 * Returns: the result of calling ToString () on an object.
7757 mono_object_to_string (MonoObject *obj, MonoObject **exc)
7760 MonoString *s = NULL;
7762 MonoMethod *method = prepare_to_string_method (obj, &target);
7764 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
7765 if (*exc == NULL && !mono_error_ok (&error))
7766 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
7768 mono_error_cleanup (&error);
7770 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
7771 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
7778 * mono_object_to_string_checked:
7780 * @error: Set on error.
7782 * Returns: the result of calling ToString () on an object. If the
7783 * method cannot be invoked or if it raises an exception, sets @error
7787 mono_object_to_string_checked (MonoObject *obj, MonoError *error)
7791 MonoMethod *method = prepare_to_string_method (obj, &target);
7792 return (MonoString*) mono_runtime_invoke_checked (method, target, NULL, error);
7796 * mono_object_try_to_string:
7798 * @exc: Any exception thrown by ToString (). Must not be NULL.
7799 * @error: Set if method cannot be invoked.
7801 * Returns: the result of calling ToString () on an object. If the
7802 * method cannot be invoked sets @error, if it raises an exception sets @exc,
7806 mono_object_try_to_string (MonoObject *obj, MonoObject **exc, MonoError *error)
7811 MonoMethod *method = prepare_to_string_method (obj, &target);
7812 return (MonoString*) mono_runtime_try_invoke (method, target, NULL, exc, error);
7818 get_native_backtrace (MonoException *exc_raw)
7820 HANDLE_FUNCTION_ENTER ();
7821 MONO_HANDLE_DCL(MonoException, exc);
7822 char * trace = mono_exception_handle_get_native_backtrace (exc);
7823 HANDLE_FUNCTION_RETURN_VAL (trace);
7827 * mono_print_unhandled_exception:
7828 * @exc: The exception
7830 * Prints the unhandled exception.
7833 mono_print_unhandled_exception (MonoObject *exc)
7835 MONO_REQ_GC_UNSAFE_MODE;
7838 char *message = (char*)"";
7839 gboolean free_message = FALSE;
7842 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
7843 message = g_strdup ("OutOfMemoryException");
7844 free_message = TRUE;
7845 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
7846 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
7847 free_message = TRUE;
7850 if (((MonoException*)exc)->native_trace_ips) {
7851 message = get_native_backtrace ((MonoException*)exc);
7852 free_message = TRUE;
7854 MonoObject *other_exc = NULL;
7855 str = mono_object_try_to_string (exc, &other_exc, &error);
7856 if (other_exc == NULL && !is_ok (&error))
7857 other_exc = (MonoObject*)mono_error_convert_to_exception (&error);
7859 mono_error_cleanup (&error);
7861 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
7862 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
7864 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
7865 original_backtrace, nested_backtrace);
7867 g_free (original_backtrace);
7868 g_free (nested_backtrace);
7869 free_message = TRUE;
7871 message = mono_string_to_utf8_checked (str, &error);
7872 if (!mono_error_ok (&error)) {
7873 mono_error_cleanup (&error);
7874 message = (char *) "";
7876 free_message = TRUE;
7883 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
7884 * exc->vtable->klass->name, message);
7886 g_printerr ("\nUnhandled Exception:\n%s\n", message);
7893 * mono_delegate_ctor_with_method:
7894 * @this: pointer to an uninitialized delegate object
7895 * @target: target object
7896 * @addr: pointer to native code
7898 * @error: set on error.
7900 * Initialize a delegate and sets a specific method, not the one
7901 * associated with addr. This is useful when sharing generic code.
7902 * In that case addr will most probably not be associated with the
7903 * correct instantiation of the method.
7904 * On failure returns FALSE and sets @error.
7907 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method, MonoError *error)
7909 MONO_REQ_GC_UNSAFE_MODE;
7912 MonoDelegate *delegate = (MonoDelegate *)this_obj;
7914 g_assert (this_obj);
7917 g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
7920 delegate->method = method;
7922 mono_stats.delegate_creations++;
7924 #ifndef DISABLE_REMOTING
7925 if (target && mono_object_is_transparent_proxy (target)) {
7927 method = mono_marshal_get_remoting_invoke (method);
7928 #ifdef ENABLE_INTERPRETER
7929 g_error ("need RuntimeMethod in method_ptr when using interpreter");
7931 delegate->method_ptr = mono_compile_method_checked (method, error);
7932 return_val_if_nok (error, FALSE);
7933 MONO_OBJECT_SETREF (delegate, target, target);
7937 delegate->method_ptr = addr;
7938 MONO_OBJECT_SETREF (delegate, target, target);
7941 delegate->invoke_impl = callbacks.create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
7942 if (callbacks.init_delegate)
7943 callbacks.init_delegate (delegate);
7948 * mono_delegate_ctor:
7949 * @this: pointer to an uninitialized delegate object
7950 * @target: target object
7951 * @addr: pointer to native code
7952 * @error: set on error.
7954 * This is used to initialize a delegate.
7955 * On failure returns FALSE and sets @error.
7958 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoError *error)
7960 MONO_REQ_GC_UNSAFE_MODE;
7963 MonoDomain *domain = mono_domain_get ();
7965 MonoMethod *method = NULL;
7969 ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
7971 if (!ji && domain != mono_get_root_domain ())
7972 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
7974 method = mono_jit_info_get_method (ji);
7975 g_assert (!mono_class_is_gtd (method->klass));
7978 return mono_delegate_ctor_with_method (this_obj, target, addr, method, error);
7982 * mono_method_call_message_new:
7983 * @method: method to encapsulate
7984 * @params: parameters to the method
7985 * @invoke: optional, delegate invoke.
7986 * @cb: async callback delegate.
7987 * @state: state passed to the async callback.
7988 * @error: set on error.
7990 * Translates arguments pointers into a MonoMethodMessage.
7991 * On failure returns NULL and sets @error.
7994 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
7995 MonoDelegate **cb, MonoObject **state, MonoError *error)
7997 MONO_REQ_GC_UNSAFE_MODE;
8001 MonoDomain *domain = mono_domain_get ();
8002 MonoMethodSignature *sig = mono_method_signature (method);
8003 MonoMethodMessage *msg;
8006 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8007 return_val_if_nok (error, NULL);
8010 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, error);
8011 return_val_if_nok (error, NULL);
8012 mono_message_init (domain, msg, rm, NULL, error);
8013 return_val_if_nok (error, NULL);
8014 count = sig->param_count - 2;
8016 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
8017 return_val_if_nok (error, NULL);
8018 mono_message_init (domain, msg, rm, NULL, error);
8019 return_val_if_nok (error, NULL);
8020 count = sig->param_count;
8023 for (i = 0; i < count; i++) {
8028 if (sig->params [i]->byref)
8029 vpos = *((gpointer *)params [i]);
8033 klass = mono_class_from_mono_type (sig->params [i]);
8035 if (klass->valuetype) {
8036 arg = mono_value_box_checked (domain, klass, vpos, error);
8037 return_val_if_nok (error, NULL);
8039 arg = *((MonoObject **)vpos);
8041 mono_array_setref (msg->args, i, arg);
8044 if (cb != NULL && state != NULL) {
8045 *cb = *((MonoDelegate **)params [i]);
8047 *state = *((MonoObject **)params [i]);
8054 * mono_method_return_message_restore:
8056 * Restore results from message based processing back to arguments pointers
8059 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args, MonoError *error)
8061 MONO_REQ_GC_UNSAFE_MODE;
8065 MonoMethodSignature *sig = mono_method_signature (method);
8066 int i, j, type, size, out_len;
8068 if (out_args == NULL)
8070 out_len = mono_array_length (out_args);
8074 for (i = 0, j = 0; i < sig->param_count; i++) {
8075 MonoType *pt = sig->params [i];
8080 mono_error_set_execution_engine (error, "The proxy call returned an incorrect number of output arguments");
8084 arg = (char *)mono_array_get (out_args, gpointer, j);
8087 g_assert (type != MONO_TYPE_VOID);
8089 if (MONO_TYPE_IS_REFERENCE (pt)) {
8090 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
8093 MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
8094 size = mono_class_value_size (klass, NULL);
8095 if (klass->has_references)
8096 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
8098 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
8100 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
8101 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
8110 #ifndef DISABLE_REMOTING
8113 * mono_load_remote_field:
8114 * @this: pointer to an object
8115 * @klass: klass of the object containing @field
8116 * @field: the field to load
8117 * @res: a storage to store the result
8119 * This method is called by the runtime on attempts to load fields of
8120 * transparent proxy objects. @this points to such TP, @klass is the class of
8121 * the object containing @field. @res is a storage location which can be
8122 * used to store the result.
8124 * Returns: an address pointing to the value of field.
8127 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
8130 gpointer result = mono_load_remote_field_checked (this_obj, klass, field, res, &error);
8131 mono_error_cleanup (&error);
8136 * mono_load_remote_field_checked:
8137 * @this: pointer to an object
8138 * @klass: klass of the object containing @field
8139 * @field: the field to load
8140 * @res: a storage to store the result
8141 * @error: set on error
8143 * This method is called by the runtime on attempts to load fields of
8144 * transparent proxy objects. @this points to such TP, @klass is the class of
8145 * the object containing @field. @res is a storage location which can be
8146 * used to store the result.
8148 * Returns: an address pointing to the value of field. On failure returns NULL and sets @error.
8151 mono_load_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res, MonoError *error)
8153 MONO_REQ_GC_UNSAFE_MODE;
8155 static MonoMethod *getter = NULL;
8159 MonoDomain *domain = mono_domain_get ();
8160 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8161 MonoClass *field_class;
8162 MonoMethodMessage *msg;
8163 MonoArray *out_args;
8167 g_assert (mono_object_is_transparent_proxy (this_obj));
8168 g_assert (res != NULL);
8170 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8171 mono_field_get_value (tp->rp->unwrapped_server, field, res);
8176 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
8178 mono_error_set_not_supported (error, "Linked away.");
8183 field_class = mono_class_from_mono_type (field->type);
8185 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8186 return_val_if_nok (error, NULL);
8187 out_args = mono_array_new_checked (domain, mono_defaults.object_class, 1, error);
8188 return_val_if_nok (error, NULL);
8189 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, error);
8190 return_val_if_nok (error, NULL);
8191 mono_message_init (domain, msg, rm, out_args, error);
8192 return_val_if_nok (error, NULL);
8194 full_name = mono_type_get_full_name (klass);
8195 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
8196 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
8199 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8200 return_val_if_nok (error, NULL);
8203 mono_error_set_exception_instance (error, (MonoException *)exc);
8207 if (mono_array_length (out_args) == 0)
8210 mono_gc_wbarrier_generic_store (res, mono_array_get (out_args, MonoObject *, 0));
8212 if (field_class->valuetype) {
8213 return ((char *)*res) + sizeof (MonoObject);
8219 * mono_load_remote_field_new:
8224 * Missing documentation.
8227 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
8231 MonoObject *result = mono_load_remote_field_new_checked (this_obj, klass, field, &error);
8232 mono_error_cleanup (&error);
8237 * mono_load_remote_field_new_checked:
8238 * @this: pointer to an object
8239 * @klass: klass of the object containing @field
8240 * @field: the field to load
8241 * @error: set on error.
8243 * This method is called by the runtime on attempts to load fields of
8244 * transparent proxy objects. @this points to such TP, @klass is the class of
8245 * the object containing @field.
8247 * Returns: a freshly allocated object containing the value of the field. On failure returns NULL and sets @error.
8250 mono_load_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoError *error)
8252 MONO_REQ_GC_UNSAFE_MODE;
8256 static MonoMethod *tp_load = NULL;
8258 g_assert (mono_object_is_transparent_proxy (this_obj));
8261 tp_load = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "LoadRemoteFieldNew", -1);
8263 mono_error_set_not_supported (error, "Linked away.");
8268 /* MonoType *type = mono_class_get_type (klass); */
8274 return mono_runtime_invoke_checked (tp_load, this_obj, args, error);
8278 * mono_store_remote_field:
8279 * @this_obj: pointer to an object
8280 * @klass: klass of the object containing @field
8281 * @field: the field to load
8282 * @val: the value/object to store
8284 * This method is called by the runtime on attempts to store fields of
8285 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
8286 * the object containing @field. @val is the new value to store in @field.
8289 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
8292 (void) mono_store_remote_field_checked (this_obj, klass, field, val, &error);
8293 mono_error_cleanup (&error);
8297 * mono_store_remote_field_checked:
8298 * @this_obj: pointer to an object
8299 * @klass: klass of the object containing @field
8300 * @field: the field to load
8301 * @val: the value/object to store
8302 * @error: set on error
8304 * This method is called by the runtime on attempts to store fields of
8305 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
8306 * the object containing @field. @val is the new value to store in @field.
8308 * Returns: on success returns TRUE, on failure returns FALSE and sets @error.
8311 mono_store_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val, MonoError *error)
8314 MONO_REQ_GC_UNSAFE_MODE;
8318 MonoDomain *domain = mono_domain_get ();
8319 MonoClass *field_class;
8322 g_assert (mono_object_is_transparent_proxy (this_obj));
8324 field_class = mono_class_from_mono_type (field->type);
8326 if (field_class->valuetype) {
8327 arg = mono_value_box_checked (domain, field_class, val, error);
8328 return_val_if_nok (error, FALSE);
8330 arg = *((MonoObject**)val);
8333 return mono_store_remote_field_new_checked (this_obj, klass, field, arg, error);
8337 * mono_store_remote_field_new:
8343 * Missing documentation
8346 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
8349 (void) mono_store_remote_field_new_checked (this_obj, klass, field, arg, &error);
8350 mono_error_cleanup (&error);
8354 * mono_store_remote_field_new_checked:
8361 * Missing documentation
8364 mono_store_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg, MonoError *error)
8366 MONO_REQ_GC_UNSAFE_MODE;
8368 static MonoMethod *tp_store = NULL;
8372 g_assert (mono_object_is_transparent_proxy (this_obj));
8375 tp_store = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "StoreRemoteField", -1);
8377 mono_error_set_not_supported (error, "Linked away.");
8387 mono_runtime_invoke_checked (tp_store, this_obj, args, error);
8388 return is_ok (error);
8393 * mono_create_ftnptr:
8395 * Given a function address, create a function descriptor for it.
8396 * This is only needed on some platforms.
8399 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
8401 return callbacks.create_ftnptr (domain, addr);
8405 * mono_get_addr_from_ftnptr:
8407 * Given a pointer to a function descriptor, return the function address.
8408 * This is only needed on some platforms.
8411 mono_get_addr_from_ftnptr (gpointer descr)
8413 return callbacks.get_addr_from_ftnptr (descr);
8417 * mono_string_chars:
8420 * Returns a pointer to the UCS16 characters stored in the MonoString
8423 mono_string_chars (MonoString *s)
8425 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
8431 * mono_string_length:
8434 * Returns the lenght in characters of the string
8437 mono_string_length (MonoString *s)
8439 MONO_REQ_GC_UNSAFE_MODE;
8445 * mono_string_handle_length:
8448 * Returns the lenght in characters of the string
8451 mono_string_handle_length (MonoStringHandle s)
8453 MONO_REQ_GC_UNSAFE_MODE;
8455 return MONO_HANDLE_GETVAL (s, length);
8460 * mono_array_length:
8461 * @array: a MonoArray*
8463 * Returns the total number of elements in the array. This works for
8464 * both vectors and multidimensional arrays.
8467 mono_array_length (MonoArray *array)
8469 MONO_REQ_GC_UNSAFE_MODE;
8471 return array->max_length;
8475 * mono_array_addr_with_size:
8476 * @array: a MonoArray*
8477 * @size: size of the array elements
8478 * @idx: index into the array
8480 * Use this function to obtain the address for the @idx item on the
8481 * @array containing elements of size @size.
8483 * This method performs no bounds checking or type checking.
8485 * Returns the address of the @idx element in the array.
8488 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
8490 MONO_REQ_GC_UNSAFE_MODE;
8492 return ((char*)(array)->vector) + size * idx;
8497 mono_glist_to_array (GList *list, MonoClass *eclass, MonoError *error)
8499 MonoDomain *domain = mono_domain_get ();
8507 len = g_list_length (list);
8508 res = mono_array_new_checked (domain, eclass, len, error);
8509 return_val_if_nok (error, NULL);
8511 for (i = 0; list; list = list->next, i++)
8512 mono_array_set (res, gpointer, i, list->data);
8519 * The following section is purely to declare prototypes and
8520 * document the API, as these C files are processed by our
8526 * @array: array to alter
8527 * @element_type: A C type name, this macro will use the sizeof(type) to determine the element size
8528 * @index: index into the array
8529 * @value: value to set
8531 * Value Type version: This sets the @index's element of the @array
8532 * with elements of size sizeof(type) to the provided @value.
8534 * This macro does not attempt to perform type checking or bounds checking.
8536 * Use this to set value types in a `MonoArray`.
8538 void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
8543 * mono_array_setref:
8544 * @array: array to alter
8545 * @index: index into the array
8546 * @value: value to set
8548 * Reference Type version: This sets the @index's element of the
8549 * @array with elements of size sizeof(type) to the provided @value.
8551 * This macro does not attempt to perform type checking or bounds checking.
8553 * Use this to reference types in a `MonoArray`.
8555 void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
8561 * @array: array on which to operate on
8562 * @element_type: C element type (example: MonoString *, int, MonoObject *)
8563 * @index: index into the array
8565 * Use this macro to retrieve the @index element of an @array and
8566 * extract the value assuming that the elements of the array match
8567 * the provided type value.
8569 * This method can be used with both arrays holding value types and
8570 * reference types. For reference types, the @type parameter should
8571 * be a `MonoObject*` or any subclass of it, like `MonoString*`.
8573 * This macro does not attempt to perform type checking or bounds checking.
8575 * Returns: The element at the @index position in the @array.
8577 Type mono_array_get (MonoArray *array, Type element_type, uintptr_t index)