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 gboolean pending_tae = FALSE;
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 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);
523 * This can happen if the cctor self-aborts. We need to reactivate tae
524 * (next interruption checkpoint will throw it) and make sure we won't
525 * throw tie for the type.
527 if (exc && mono_object_class (exc) == mono_defaults.threadabortexception_class) {
529 mono_thread_resume_interruption (FALSE);
532 /* this just blocks until the initializing thread is done */
533 mono_type_init_lock (lock);
535 mono_coop_cond_wait (&lock->cond, &lock->mutex);
536 mono_type_init_unlock (lock);
539 /* Do cleanup and setting vtable->initialized inside the global lock again */
540 mono_type_initialization_lock ();
541 if (!do_initialization)
542 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
543 gboolean deleted = unref_type_lock (lock);
545 g_hash_table_remove (type_initialization_hash, vtable);
546 /* Have to set this here since we check it inside the global lock */
547 if (do_initialization && !vtable->init_failed)
548 vtable->initialized = 1;
549 mono_type_initialization_unlock ();
551 /* If vtable init fails because of TAE, we don't throw TIE, only the TAE */
552 if (vtable->init_failed && !pending_tae) {
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 gboolean was_null = FALSE;
4834 if (!mono_array_get (params, MonoObject*, i)) {
4835 MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (t_orig), error);
4836 return_val_if_nok (error, NULL);
4837 mono_array_setref (params, i, o);
4843 * We can't pass the unboxed vtype byref to the callee, since
4844 * that would mean the callee would be able to modify boxed
4845 * primitive types. So we (and MS) make a copy of the boxed
4846 * object, pass that to the callee, and replace the original
4847 * boxed object in the arg array with the copy.
4849 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4850 MonoObject *copy = mono_value_box_checked (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig), error);
4851 return_val_if_nok (error, NULL);
4852 mono_array_setref (params, i, copy);
4855 result = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4856 if (!t->byref && was_null)
4857 mono_array_setref (params, i, NULL);
4860 case MONO_TYPE_STRING:
4861 case MONO_TYPE_OBJECT:
4862 case MONO_TYPE_CLASS:
4863 case MONO_TYPE_ARRAY:
4864 case MONO_TYPE_SZARRAY:
4866 result = mono_array_addr (params, MonoObject*, i);
4867 // FIXME: I need to check this code path
4869 result = mono_array_get (params, MonoObject*, i);
4871 case MONO_TYPE_GENERICINST:
4873 t = &t->data.generic_class->container_class->this_arg;
4875 t = &t->data.generic_class->container_class->byval_arg;
4877 case MONO_TYPE_PTR: {
4880 /* The argument should be an IntPtr */
4881 arg = mono_array_get (params, MonoObject*, i);
4885 g_assert (arg->vtable->klass == mono_defaults.int_class);
4886 result = ((MonoIntPtr*)arg)->m_value;
4891 g_error ("type 0x%x not handled in mono_runtime_invoke_array", t_orig->type);
4896 * mono_runtime_invoke_array:
4897 * @method: method to invoke
4898 * @obJ: object instance
4899 * @params: arguments to the method
4900 * @exc: exception information.
4902 * Invokes the method represented by @method on the object @obj.
4904 * obj is the 'this' pointer, it should be NULL for static
4905 * methods, a MonoObject* for object instances and a pointer to
4906 * the value type for value types.
4908 * The params array contains the arguments to the method with the
4909 * same convention: MonoObject* pointers for object instances and
4910 * pointers to the value type otherwise. The _invoke_array
4911 * variant takes a C# object[] as the params argument (MonoArray
4912 * *params): in this case the value types are boxed inside the
4913 * respective reference representation.
4915 * From unmanaged code you'll usually use the
4916 * mono_runtime_invoke_checked() variant.
4918 * Note that this function doesn't handle virtual methods for
4919 * you, it will exec the exact method you pass: we still need to
4920 * expose a function to lookup the derived class implementation
4921 * of a virtual method (there are examples of this in the code,
4924 * You can pass NULL as the exc argument if you don't want to
4925 * catch exceptions, otherwise, *exc will be set to the exception
4926 * thrown, if any. if an exception is thrown, you can't use the
4927 * MonoObject* result from the function.
4929 * If the method returns a value type, it is boxed in an object
4933 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4938 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, exc, &error);
4940 mono_error_cleanup (&error);
4943 if (!is_ok (&error))
4944 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
4948 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, NULL, &error);
4949 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
4955 * mono_runtime_invoke_array_checked:
4956 * @method: method to invoke
4957 * @obJ: object instance
4958 * @params: arguments to the method
4959 * @error: set on failure.
4961 * Invokes the method represented by @method on the object @obj.
4963 * obj is the 'this' pointer, it should be NULL for static
4964 * methods, a MonoObject* for object instances and a pointer to
4965 * the value type for value types.
4967 * The params array contains the arguments to the method with the
4968 * same convention: MonoObject* pointers for object instances and
4969 * pointers to the value type otherwise. The _invoke_array
4970 * variant takes a C# object[] as the params argument (MonoArray
4971 * *params): in this case the value types are boxed inside the
4972 * respective reference representation.
4974 * From unmanaged code you'll usually use the
4975 * mono_runtime_invoke_checked() variant.
4977 * Note that this function doesn't handle virtual methods for
4978 * you, it will exec the exact method you pass: we still need to
4979 * expose a function to lookup the derived class implementation
4980 * of a virtual method (there are examples of this in the code,
4983 * On failure or exception, @error will be set. In that case, you
4984 * can't use the MonoObject* result from the function.
4986 * If the method returns a value type, it is boxed in an object
4990 mono_runtime_invoke_array_checked (MonoMethod *method, void *obj, MonoArray *params,
4994 return mono_runtime_try_invoke_array (method, obj, params, NULL, error);
4998 * mono_runtime_try_invoke_array:
4999 * @method: method to invoke
5000 * @obJ: object instance
5001 * @params: arguments to the method
5002 * @exc: exception information.
5003 * @error: set on failure.
5005 * Invokes the method represented by @method on the object @obj.
5007 * obj is the 'this' pointer, it should be NULL for static
5008 * methods, a MonoObject* for object instances and a pointer to
5009 * the value type for value types.
5011 * The params array contains the arguments to the method with the
5012 * same convention: MonoObject* pointers for object instances and
5013 * pointers to the value type otherwise. The _invoke_array
5014 * variant takes a C# object[] as the params argument (MonoArray
5015 * *params): in this case the value types are boxed inside the
5016 * respective reference representation.
5018 * From unmanaged code you'll usually use the
5019 * mono_runtime_invoke_checked() variant.
5021 * Note that this function doesn't handle virtual methods for
5022 * you, it will exec the exact method you pass: we still need to
5023 * expose a function to lookup the derived class implementation
5024 * of a virtual method (there are examples of this in the code,
5027 * You can pass NULL as the exc argument if you don't want to catch
5028 * exceptions, otherwise, *exc will be set to the exception thrown, if
5029 * any. On other failures, @error will be set. If an exception is
5030 * thrown or there's an error, you can't use the MonoObject* result
5031 * from the function.
5033 * If the method returns a value type, it is boxed in an object
5037 mono_runtime_try_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
5038 MonoObject **exc, MonoError *error)
5040 MONO_REQ_GC_UNSAFE_MODE;
5044 MonoMethodSignature *sig = mono_method_signature (method);
5045 gpointer *pa = NULL;
5048 gboolean has_byref_nullables = FALSE;
5050 if (NULL != params) {
5051 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
5052 for (i = 0; i < mono_array_length (params); i++) {
5053 MonoType *t = sig->params [i];
5054 pa [i] = invoke_array_extract_argument (params, i, t, &has_byref_nullables, error);
5055 return_val_if_nok (error, NULL);
5059 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
5062 if (mono_class_is_nullable (method->klass)) {
5063 /* Need to create a boxed vtype instead */
5069 return mono_value_box_checked (mono_domain_get (), method->klass->cast_class, pa [0], error);
5074 obj = mono_object_new_checked (mono_domain_get (), method->klass, error);
5075 mono_error_assert_ok (error);
5076 g_assert (obj); /*maybe we should raise a TLE instead?*/
5077 #ifndef DISABLE_REMOTING
5078 if (mono_object_is_transparent_proxy (obj)) {
5079 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
5082 if (method->klass->valuetype)
5083 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
5086 } else if (method->klass->valuetype) {
5087 obj = mono_value_box_checked (mono_domain_get (), method->klass, obj, error);
5088 return_val_if_nok (error, NULL);
5092 mono_runtime_try_invoke (method, o, pa, exc, error);
5094 mono_runtime_invoke_checked (method, o, pa, error);
5097 return (MonoObject *)obj;
5099 if (mono_class_is_nullable (method->klass)) {
5100 MonoObject *nullable;
5102 /* Convert the unboxed vtype into a Nullable structure */
5103 nullable = mono_object_new_checked (mono_domain_get (), method->klass, error);
5104 return_val_if_nok (error, NULL);
5106 MonoObject *boxed = mono_value_box_checked (mono_domain_get (), method->klass->cast_class, obj, error);
5107 return_val_if_nok (error, NULL);
5108 mono_nullable_init ((guint8 *)mono_object_unbox (nullable), boxed, method->klass);
5109 obj = mono_object_unbox (nullable);
5112 /* obj must be already unboxed if needed */
5114 res = mono_runtime_try_invoke (method, obj, pa, exc, error);
5116 res = mono_runtime_invoke_checked (method, obj, pa, error);
5118 return_val_if_nok (error, NULL);
5120 if (sig->ret->type == MONO_TYPE_PTR) {
5121 MonoClass *pointer_class;
5122 static MonoMethod *box_method;
5124 MonoObject *box_exc;
5127 * The runtime-invoke wrapper returns a boxed IntPtr, need to
5128 * convert it to a Pointer object.
5130 pointer_class = mono_class_get_pointer_class ();
5132 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
5134 g_assert (res->vtable->klass == mono_defaults.int_class);
5135 box_args [0] = ((MonoIntPtr*)res)->m_value;
5136 box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, error);
5137 return_val_if_nok (error, NULL);
5139 res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, error);
5140 g_assert (box_exc == NULL);
5141 mono_error_assert_ok (error);
5144 if (has_byref_nullables) {
5146 * The runtime invoke wrapper already converted byref nullables back,
5147 * and stored them in pa, we just need to copy them back to the
5150 for (i = 0; i < mono_array_length (params); i++) {
5151 MonoType *t = sig->params [i];
5153 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
5154 mono_array_setref (params, i, pa [i]);
5164 * @klass: the class of the object that we want to create
5166 * Returns: a newly created object whose definition is
5167 * looked up using @klass. This will not invoke any constructors,
5168 * so the consumer of this routine has to invoke any constructors on
5169 * its own to initialize the object.
5171 * It returns NULL on failure.
5174 mono_object_new (MonoDomain *domain, MonoClass *klass)
5176 MONO_REQ_GC_UNSAFE_MODE;
5180 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5182 mono_error_cleanup (&error);
5187 ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
5189 MONO_REQ_GC_UNSAFE_MODE;
5193 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5195 mono_error_set_pending_exception (&error);
5200 * mono_object_new_checked:
5201 * @klass: the class of the object that we want to create
5202 * @error: set on error
5204 * Returns: a newly created object whose definition is
5205 * looked up using @klass. This will not invoke any constructors,
5206 * so the consumer of this routine has to invoke any constructors on
5207 * its own to initialize the object.
5209 * It returns NULL on failure and sets @error.
5212 mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
5214 MONO_REQ_GC_UNSAFE_MODE;
5218 vtable = mono_class_vtable (domain, klass);
5219 g_assert (vtable); /* FIXME don't swallow the error */
5221 MonoObject *o = mono_object_new_specific_checked (vtable, error);
5226 * mono_object_new_pinned:
5228 * Same as mono_object_new, but the returned object will be pinned.
5229 * For SGEN, these objects will only be freed at appdomain unload.
5232 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
5234 MONO_REQ_GC_UNSAFE_MODE;
5240 vtable = mono_class_vtable (domain, klass);
5241 g_assert (vtable); /* FIXME don't swallow the error */
5243 MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
5245 if (G_UNLIKELY (!o))
5246 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
5247 else if (G_UNLIKELY (vtable->klass->has_finalize))
5248 mono_object_register_finalizer (o);
5254 * mono_object_new_specific:
5255 * @vtable: the vtable of the object that we want to create
5257 * Returns: A newly created object with class and domain specified
5261 mono_object_new_specific (MonoVTable *vtable)
5264 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5265 mono_error_cleanup (&error);
5271 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
5273 MONO_REQ_GC_UNSAFE_MODE;
5279 /* check for is_com_object for COM Interop */
5280 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
5283 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
5286 MonoClass *klass = mono_class_get_activation_services_class ();
5289 mono_class_init (klass);
5291 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
5293 mono_error_set_not_supported (error, "Linked away.");
5296 vtable->domain->create_proxy_for_type_method = im;
5299 pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
5300 if (!mono_error_ok (error))
5303 o = mono_runtime_invoke_checked (im, NULL, pa, error);
5304 if (!mono_error_ok (error))
5311 return mono_object_new_alloc_specific_checked (vtable, error);
5315 ves_icall_object_new_specific (MonoVTable *vtable)
5318 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5319 mono_error_set_pending_exception (&error);
5325 * mono_object_new_alloc_specific:
5326 * @vtable: virtual table for the object.
5328 * This function allocates a new `MonoObject` with the type derived
5329 * from the @vtable information. If the class of this object has a
5330 * finalizer, then the object will be tracked for finalization.
5332 * This method might raise an exception on errors. Use the
5333 * `mono_object_new_fast_checked` method if you want to manually raise
5336 * Returns: the allocated object.
5339 mono_object_new_alloc_specific (MonoVTable *vtable)
5342 MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
5343 mono_error_cleanup (&error);
5349 * mono_object_new_alloc_specific_checked:
5350 * @vtable: virtual table for the object.
5351 * @error: holds the error return value.
5353 * This function allocates a new `MonoObject` with the type derived
5354 * from the @vtable information. If the class of this object has a
5355 * finalizer, then the object will be tracked for finalization.
5357 * If there is not enough memory, the @error parameter will be set
5358 * and will contain a user-visible message with the amount of bytes
5359 * that were requested.
5361 * Returns: the allocated object, or NULL if there is not enough memory
5365 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
5367 MONO_REQ_GC_UNSAFE_MODE;
5373 o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5375 if (G_UNLIKELY (!o))
5376 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5377 else if (G_UNLIKELY (vtable->klass->has_finalize))
5378 mono_object_register_finalizer (o);
5384 * mono_object_new_fast:
5385 * @vtable: virtual table for the object.
5387 * This function allocates a new `MonoObject` with the type derived
5388 * from the @vtable information. The returned object is not tracked
5389 * for finalization. If your object implements a finalizer, you should
5390 * use `mono_object_new_alloc_specific` instead.
5392 * This method might raise an exception on errors. Use the
5393 * `mono_object_new_fast_checked` method if you want to manually raise
5396 * Returns: the allocated object.
5399 mono_object_new_fast (MonoVTable *vtable)
5402 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5403 mono_error_cleanup (&error);
5409 * mono_object_new_fast_checked:
5410 * @vtable: virtual table for the object.
5411 * @error: holds the error return value.
5413 * This function allocates a new `MonoObject` with the type derived
5414 * from the @vtable information. The returned object is not tracked
5415 * for finalization. If your object implements a finalizer, you should
5416 * use `mono_object_new_alloc_specific_checked` instead.
5418 * If there is not enough memory, the @error parameter will be set
5419 * and will contain a user-visible message with the amount of bytes
5420 * that were requested.
5422 * Returns: the allocated object, or NULL if there is not enough memory
5426 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
5428 MONO_REQ_GC_UNSAFE_MODE;
5434 o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5436 if (G_UNLIKELY (!o))
5437 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5443 ves_icall_object_new_fast (MonoVTable *vtable)
5446 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5447 mono_error_set_pending_exception (&error);
5453 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
5455 MONO_REQ_GC_UNSAFE_MODE;
5461 o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
5463 if (G_UNLIKELY (!o))
5464 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5465 else if (G_UNLIKELY (vtable->klass->has_finalize))
5466 mono_object_register_finalizer (o);
5472 * mono_class_get_allocation_ftn:
5474 * @for_box: the object will be used for boxing
5475 * @pass_size_in_words:
5477 * Return the allocation function appropriate for the given class.
5481 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
5483 MONO_REQ_GC_NEUTRAL_MODE;
5485 *pass_size_in_words = FALSE;
5487 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass))
5488 return ves_icall_object_new_specific;
5490 if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
5492 return ves_icall_object_new_fast;
5495 * FIXME: This is actually slower than ves_icall_object_new_fast, because
5496 * of the overhead of parameter passing.
5499 *pass_size_in_words = TRUE;
5500 #ifdef GC_REDIRECT_TO_LOCAL
5501 return GC_local_gcj_fast_malloc;
5503 return GC_gcj_fast_malloc;
5508 return ves_icall_object_new_specific;
5512 * mono_object_new_from_token:
5513 * @image: Context where the type_token is hosted
5514 * @token: a token of the type that we want to create
5516 * Returns: A newly created object whose definition is
5517 * looked up using @token in the @image image
5520 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
5522 MONO_REQ_GC_UNSAFE_MODE;
5528 klass = mono_class_get_checked (image, token, &error);
5529 mono_error_assert_ok (&error);
5531 result = mono_object_new_checked (domain, klass, &error);
5533 mono_error_cleanup (&error);
5540 * mono_object_clone:
5541 * @obj: the object to clone
5543 * Returns: A newly created object who is a shallow copy of @obj
5546 mono_object_clone (MonoObject *obj)
5549 MonoObject *o = mono_object_clone_checked (obj, &error);
5550 mono_error_cleanup (&error);
5556 mono_object_clone_checked (MonoObject *obj, MonoError *error)
5558 MONO_REQ_GC_UNSAFE_MODE;
5565 size = obj->vtable->klass->instance_size;
5567 if (obj->vtable->klass->rank)
5568 return (MonoObject*)mono_array_clone_checked ((MonoArray*)obj, error);
5570 o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
5572 if (G_UNLIKELY (!o)) {
5573 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5577 /* If the object doesn't contain references this will do a simple memmove. */
5578 mono_gc_wbarrier_object_copy (o, obj);
5580 if (obj->vtable->klass->has_finalize)
5581 mono_object_register_finalizer (o);
5586 * mono_array_full_copy:
5587 * @src: source array to copy
5588 * @dest: destination array
5590 * Copies the content of one array to another with exactly the same type and size.
5593 mono_array_full_copy (MonoArray *src, MonoArray *dest)
5595 MONO_REQ_GC_UNSAFE_MODE;
5598 MonoClass *klass = src->obj.vtable->klass;
5600 g_assert (klass == dest->obj.vtable->klass);
5602 size = mono_array_length (src);
5603 g_assert (size == mono_array_length (dest));
5604 size *= mono_array_element_size (klass);
5606 array_full_copy_unchecked_size (src, dest, klass, size);
5610 array_full_copy_unchecked_size (MonoArray *src, MonoArray *dest, MonoClass *klass, uintptr_t size)
5613 if (klass->element_class->valuetype) {
5614 if (klass->element_class->has_references)
5615 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
5617 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5619 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
5622 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5627 * mono_array_clone_in_domain:
5628 * @domain: the domain in which the array will be cloned into
5629 * @array: the array to clone
5630 * @error: set on error
5632 * This routine returns a copy of the array that is hosted on the
5633 * specified MonoDomain. On failure returns NULL and sets @error.
5636 mono_array_clone_in_domain (MonoDomain *domain, MonoArrayHandle array_handle, MonoError *error)
5638 MONO_REQ_GC_UNSAFE_MODE;
5640 MonoArrayHandle result = MONO_HANDLE_NEW (MonoArray, NULL);
5642 MonoClass *klass = mono_handle_class (array_handle);
5646 /* Pin source array here - if bounds is non-NULL, it's a pointer into the object data */
5647 uint32_t src_handle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, array_handle), TRUE);
5649 MonoArrayBounds *array_bounds = MONO_HANDLE_GETVAL (array_handle, bounds);
5651 if (array_bounds == NULL) {
5652 size = mono_array_handle_length (array_handle);
5653 o = mono_array_new_full_handle (domain, klass, &size, NULL, error);
5656 size *= mono_array_element_size (klass);
5658 uintptr_t *sizes = (uintptr_t *)alloca (klass->rank * sizeof (uintptr_t));
5659 intptr_t *lower_bounds = (intptr_t *)alloca (klass->rank * sizeof (intptr_t));
5660 size = mono_array_element_size (klass);
5661 for (int i = 0; i < klass->rank; ++i) {
5662 sizes [i] = array_bounds [i].length;
5663 size *= array_bounds [i].length;
5664 lower_bounds [i] = array_bounds [i].lower_bound;
5666 o = mono_array_new_full_handle (domain, klass, sizes, lower_bounds, error);
5671 uint32_t dst_handle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, o), TRUE);
5672 array_full_copy_unchecked_size (MONO_HANDLE_RAW (array_handle), MONO_HANDLE_RAW (o), klass, size);
5673 mono_gchandle_free (dst_handle);
5675 MONO_HANDLE_ASSIGN (result, o);
5678 mono_gchandle_free (src_handle);
5684 * @array: the array to clone
5686 * Returns: A newly created array who is a shallow copy of @array
5689 mono_array_clone (MonoArray *array)
5691 MONO_REQ_GC_UNSAFE_MODE;
5694 MonoArray *result = mono_array_clone_checked (array, &error);
5695 mono_error_cleanup (&error);
5700 * mono_array_clone_checked:
5701 * @array: the array to clone
5702 * @error: set on error
5704 * Returns: A newly created array who is a shallow copy of @array. On
5705 * failure returns NULL and sets @error.
5708 mono_array_clone_checked (MonoArray *array_raw, MonoError *error)
5710 MONO_REQ_GC_UNSAFE_MODE;
5711 HANDLE_FUNCTION_ENTER ();
5712 /* FIXME: callers of mono_array_clone_checked should use handles */
5714 MONO_HANDLE_DCL (MonoArray, array);
5715 MonoArrayHandle result = mono_array_clone_in_domain (MONO_HANDLE_DOMAIN (array), array, error);
5716 HANDLE_FUNCTION_RETURN_OBJ (result);
5719 /* helper macros to check for overflow when calculating the size of arrays */
5720 #ifdef MONO_BIG_ARRAYS
5721 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
5722 #define MYGUINT_MAX MYGUINT64_MAX
5723 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5724 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
5725 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5726 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
5727 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
5729 #define MYGUINT32_MAX 4294967295U
5730 #define MYGUINT_MAX MYGUINT32_MAX
5731 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5732 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
5733 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5734 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
5735 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
5739 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
5741 MONO_REQ_GC_NEUTRAL_MODE;
5745 byte_len = mono_array_element_size (klass);
5746 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
5749 if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
5751 byte_len += MONO_SIZEOF_MONO_ARRAY;
5759 * mono_array_new_full:
5760 * @domain: domain where the object is created
5761 * @array_class: array class
5762 * @lengths: lengths for each dimension in the array
5763 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
5765 * This routine creates a new array objects with the given dimensions,
5766 * lower bounds and type.
5769 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
5772 MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
5773 mono_error_cleanup (&error);
5779 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
5781 MONO_REQ_GC_UNSAFE_MODE;
5783 uintptr_t byte_len = 0, len, bounds_size;
5786 MonoArrayBounds *bounds;
5792 if (!array_class->inited)
5793 mono_class_init (array_class);
5797 /* A single dimensional array with a 0 lower bound is the same as an szarray */
5798 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
5800 if (len > MONO_ARRAY_MAX_INDEX) {
5801 mono_error_set_generic_error (error, "System", "OverflowException", "");
5806 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
5808 for (i = 0; i < array_class->rank; ++i) {
5809 if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
5810 mono_error_set_generic_error (error, "System", "OverflowException", "");
5813 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5814 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5821 if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5822 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5828 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5829 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5832 byte_len = (byte_len + 3) & ~3;
5833 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5834 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5837 byte_len += bounds_size;
5840 * Following three lines almost taken from mono_object_new ():
5841 * they need to be kept in sync.
5843 vtable = mono_class_vtable_full (domain, array_class, error);
5844 return_val_if_nok (error, NULL);
5847 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5849 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5851 if (G_UNLIKELY (!o)) {
5852 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5856 array = (MonoArray*)o;
5858 bounds = array->bounds;
5861 for (i = 0; i < array_class->rank; ++i) {
5862 bounds [i].length = lengths [i];
5864 bounds [i].lower_bound = lower_bounds [i];
5873 * @domain: domain where the object is created
5874 * @eclass: element class
5875 * @n: number of array elements
5877 * This routine creates a new szarray with @n elements of type @eclass.
5880 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5882 MONO_REQ_GC_UNSAFE_MODE;
5885 MonoArray *result = mono_array_new_checked (domain, eclass, n, &error);
5886 mono_error_cleanup (&error);
5891 * mono_array_new_checked:
5892 * @domain: domain where the object is created
5893 * @eclass: element class
5894 * @n: number of array elements
5895 * @error: set on error
5897 * This routine creates a new szarray with @n elements of type @eclass.
5898 * On failure returns NULL and sets @error.
5901 mono_array_new_checked (MonoDomain *domain, MonoClass *eclass, uintptr_t n, MonoError *error)
5907 ac = mono_array_class_get (eclass, 1);
5910 MonoVTable *vtable = mono_class_vtable_full (domain, ac, error);
5911 return_val_if_nok (error, NULL);
5913 return mono_array_new_specific_checked (vtable, n, error);
5917 ves_icall_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5920 MonoArray *arr = mono_array_new_checked (domain, eclass, n, &error);
5921 mono_error_set_pending_exception (&error);
5927 * mono_array_new_specific:
5928 * @vtable: a vtable in the appropriate domain for an initialized class
5929 * @n: number of array elements
5931 * This routine is a fast alternative to mono_array_new() for code which
5932 * can be sure about the domain it operates in.
5935 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5938 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5939 mono_error_cleanup (&error);
5945 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
5947 MONO_REQ_GC_UNSAFE_MODE;
5954 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
5955 mono_error_set_generic_error (error, "System", "OverflowException", "");
5959 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
5960 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5963 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
5965 if (G_UNLIKELY (!o)) {
5966 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5970 return (MonoArray*)o;
5974 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
5977 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5978 mono_error_set_pending_exception (&error);
5984 * mono_string_empty_wrapper:
5986 * Returns: The same empty string instance as the managed string.Empty
5989 mono_string_empty_wrapper (void)
5991 MonoDomain *domain = mono_domain_get ();
5992 return mono_string_empty (domain);
5996 * mono_string_empty:
5998 * Returns: The same empty string instance as the managed string.Empty
6001 mono_string_empty (MonoDomain *domain)
6004 g_assert (domain->empty_string);
6005 return domain->empty_string;
6009 * mono_string_new_utf16:
6010 * @text: a pointer to an utf16 string
6011 * @len: the length of the string
6013 * Returns: A newly created string object which contains @text.
6016 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
6018 MONO_REQ_GC_UNSAFE_MODE;
6021 MonoString *res = NULL;
6022 res = mono_string_new_utf16_checked (domain, text, len, &error);
6023 mono_error_cleanup (&error);
6029 * mono_string_new_utf16_checked:
6030 * @text: a pointer to an utf16 string
6031 * @len: the length of the string
6032 * @error: written on error.
6034 * Returns: A newly created string object which contains @text.
6035 * On error, returns NULL and sets @error.
6038 mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
6040 MONO_REQ_GC_UNSAFE_MODE;
6046 s = mono_string_new_size_checked (domain, len, error);
6048 memcpy (mono_string_chars (s), text, len * 2);
6054 * mono_string_new_utf16_handle:
6055 * @text: a pointer to an utf16 string
6056 * @len: the length of the string
6057 * @error: written on error.
6059 * Returns: A newly created string object which contains @text.
6060 * On error, returns NULL and sets @error.
6063 mono_string_new_utf16_handle (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
6065 return MONO_HANDLE_NEW (MonoString, mono_string_new_utf16_checked (domain, text, len, error));
6069 * mono_string_new_utf32:
6070 * @text: a pointer to an utf32 string
6071 * @len: the length of the string
6072 * @error: set on failure.
6074 * Returns: A newly created string object which contains @text. On failure returns NULL and sets @error.
6077 mono_string_new_utf32_checked (MonoDomain *domain, const mono_unichar4 *text, gint32 len, MonoError *error)
6079 MONO_REQ_GC_UNSAFE_MODE;
6082 mono_unichar2 *utf16_output = NULL;
6083 gint32 utf16_len = 0;
6084 GError *gerror = NULL;
6085 glong items_written;
6088 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
6091 g_error_free (gerror);
6093 while (utf16_output [utf16_len]) utf16_len++;
6095 s = mono_string_new_size_checked (domain, utf16_len, error);
6096 return_val_if_nok (error, NULL);
6098 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
6100 g_free (utf16_output);
6106 * mono_string_new_utf32:
6107 * @text: a pointer to an utf32 string
6108 * @len: the length of the string
6110 * Returns: A newly created string object which contains @text.
6113 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
6116 MonoString *result = mono_string_new_utf32_checked (domain, text, len, &error);
6117 mono_error_cleanup (&error);
6122 * mono_string_new_size:
6123 * @text: a pointer to an utf16 string
6124 * @len: the length of the string
6126 * Returns: A newly created string object of @len
6129 mono_string_new_size (MonoDomain *domain, gint32 len)
6132 MonoString *str = mono_string_new_size_checked (domain, len, &error);
6133 mono_error_cleanup (&error);
6139 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
6141 MONO_REQ_GC_UNSAFE_MODE;
6149 /* check for overflow */
6150 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
6151 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
6155 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
6156 g_assert (size > 0);
6158 vtable = mono_class_vtable (domain, mono_defaults.string_class);
6161 s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
6163 if (G_UNLIKELY (!s)) {
6164 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", size);
6172 * mono_string_new_len:
6173 * @text: a pointer to an utf8 string
6174 * @length: number of bytes in @text to consider
6176 * Returns: A newly created string object which contains @text.
6179 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
6181 MONO_REQ_GC_UNSAFE_MODE;
6184 MonoString *result = mono_string_new_len_checked (domain, text, length, &error);
6185 mono_error_cleanup (&error);
6190 * mono_string_new_len_checked:
6191 * @text: a pointer to an utf8 string
6192 * @length: number of bytes in @text to consider
6193 * @error: set on error
6195 * Returns: A newly created string object which contains @text. On
6196 * failure returns NULL and sets @error.
6199 mono_string_new_len_checked (MonoDomain *domain, const char *text, guint length, MonoError *error)
6201 MONO_REQ_GC_UNSAFE_MODE;
6205 GError *eg_error = NULL;
6206 MonoString *o = NULL;
6208 glong items_written;
6210 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
6213 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6215 g_error_free (eg_error);
6224 * @text: a pointer to an utf8 string
6226 * Returns: A newly created string object which contains @text.
6228 * This function asserts if it cannot allocate a new string.
6230 * @deprecated Use mono_string_new_checked in new code.
6233 mono_string_new (MonoDomain *domain, const char *text)
6236 MonoString *res = NULL;
6237 res = mono_string_new_checked (domain, text, &error);
6238 mono_error_assert_ok (&error);
6243 * mono_string_new_checked:
6244 * @text: a pointer to an utf8 string
6245 * @merror: set on error
6247 * Returns: A newly created string object which contains @text.
6248 * On error returns NULL and sets @merror.
6251 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
6253 MONO_REQ_GC_UNSAFE_MODE;
6255 GError *eg_error = NULL;
6256 MonoString *o = NULL;
6258 glong items_written;
6265 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &eg_error);
6268 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6270 g_error_free (eg_error);
6274 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
6279 MonoString *o = NULL;
6281 if (!g_utf8_validate (text, -1, &end)) {
6282 mono_error_set_argument (error, "text", "Not a valid utf8 string");
6286 len = g_utf8_strlen (text, -1);
6287 o = mono_string_new_size_checked (domain, len, error);
6290 str = mono_string_chars (o);
6292 while (text < end) {
6293 *str++ = g_utf8_get_char (text);
6294 text = g_utf8_next_char (text);
6303 * mono_string_new_wrapper:
6304 * @text: pointer to utf8 characters.
6306 * Helper function to create a string object from @text in the current domain.
6309 mono_string_new_wrapper (const char *text)
6311 MONO_REQ_GC_UNSAFE_MODE;
6313 MonoDomain *domain = mono_domain_get ();
6316 return mono_string_new (domain, text);
6323 * @class: the class of the value
6324 * @value: a pointer to the unboxed data
6326 * Returns: A newly created object which contains @value.
6329 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
6332 MonoObject *result = mono_value_box_checked (domain, klass, value, &error);
6333 mono_error_cleanup (&error);
6338 * mono_value_box_checked:
6339 * @domain: the domain of the new object
6340 * @class: the class of the value
6341 * @value: a pointer to the unboxed data
6342 * @error: set on error
6344 * Returns: A newly created object which contains @value. On failure
6345 * returns NULL and sets @error.
6348 mono_value_box_checked (MonoDomain *domain, MonoClass *klass, gpointer value, MonoError *error)
6350 MONO_REQ_GC_UNSAFE_MODE;
6357 g_assert (klass->valuetype);
6358 if (mono_class_is_nullable (klass))
6359 return mono_nullable_box ((guint8 *)value, klass, error);
6361 vtable = mono_class_vtable (domain, klass);
6364 size = mono_class_instance_size (klass);
6365 res = mono_object_new_alloc_specific_checked (vtable, error);
6366 return_val_if_nok (error, NULL);
6368 size = size - sizeof (MonoObject);
6371 g_assert (size == mono_class_value_size (klass, NULL));
6372 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
6374 #if NO_UNALIGNED_ACCESS
6375 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6379 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
6382 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
6385 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
6388 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
6391 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6395 if (klass->has_finalize) {
6396 mono_object_register_finalizer (res);
6397 return_val_if_nok (error, NULL);
6404 * @dest: destination pointer
6405 * @src: source pointer
6406 * @klass: a valuetype class
6408 * Copy a valuetype from @src to @dest. This function must be used
6409 * when @klass contains references fields.
6412 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
6414 MONO_REQ_GC_UNSAFE_MODE;
6416 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
6420 * mono_value_copy_array:
6421 * @dest: destination array
6422 * @dest_idx: index in the @dest array
6423 * @src: source pointer
6424 * @count: number of items
6426 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
6427 * This function must be used when @klass contains references fields.
6428 * Overlap is handled.
6431 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
6433 MONO_REQ_GC_UNSAFE_MODE;
6435 int size = mono_array_element_size (dest->obj.vtable->klass);
6436 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
6437 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
6438 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
6442 * mono_object_get_domain:
6443 * @obj: object to query
6445 * Returns: the MonoDomain where the object is hosted
6448 mono_object_get_domain (MonoObject *obj)
6450 MONO_REQ_GC_UNSAFE_MODE;
6452 return mono_object_domain (obj);
6456 * mono_object_get_class:
6457 * @obj: object to query
6459 * Use this function to obtain the `MonoClass*` for a given `MonoObject`.
6461 * Returns: the MonoClass of the object.
6464 mono_object_get_class (MonoObject *obj)
6466 MONO_REQ_GC_UNSAFE_MODE;
6468 return mono_object_class (obj);
6471 * mono_object_get_size:
6472 * @o: object to query
6474 * Returns: the size, in bytes, of @o
6477 mono_object_get_size (MonoObject* o)
6479 MONO_REQ_GC_UNSAFE_MODE;
6481 MonoClass* klass = mono_object_class (o);
6482 if (klass == mono_defaults.string_class) {
6483 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
6484 } else if (o->vtable->rank) {
6485 MonoArray *array = (MonoArray*)o;
6486 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
6487 if (array->bounds) {
6490 size += sizeof (MonoArrayBounds) * o->vtable->rank;
6494 return mono_class_instance_size (klass);
6499 * mono_object_unbox:
6500 * @obj: object to unbox
6502 * Returns: a pointer to the start of the valuetype boxed in this
6505 * This method will assert if the object passed is not a valuetype.
6508 mono_object_unbox (MonoObject *obj)
6510 MONO_REQ_GC_UNSAFE_MODE;
6512 /* add assert for valuetypes? */
6513 g_assert (obj->vtable->klass->valuetype);
6514 return ((char*)obj) + sizeof (MonoObject);
6518 * mono_object_isinst:
6520 * @klass: a pointer to a class
6522 * Returns: @obj if @obj is derived from @klass or NULL otherwise.
6525 mono_object_isinst (MonoObject *obj_raw, MonoClass *klass)
6527 MONO_REQ_GC_UNSAFE_MODE;
6529 HANDLE_FUNCTION_ENTER ();
6530 MONO_HANDLE_DCL (MonoObject, obj);
6532 MonoObjectHandle result = mono_object_handle_isinst (obj, klass, &error);
6533 mono_error_cleanup (&error);
6534 HANDLE_FUNCTION_RETURN_OBJ (result);
6539 * mono_object_isinst_checked:
6541 * @klass: a pointer to a class
6542 * @error: set on error
6544 * Returns: @obj if @obj is derived from @klass or NULL if it isn't.
6545 * On failure returns NULL and sets @error.
6548 mono_object_isinst_checked (MonoObject *obj_raw, MonoClass *klass, MonoError *error)
6550 MONO_REQ_GC_UNSAFE_MODE;
6552 HANDLE_FUNCTION_ENTER ();
6554 MONO_HANDLE_DCL (MonoObject, obj);
6555 MonoObjectHandle result = mono_object_handle_isinst (obj, klass, error);
6556 HANDLE_FUNCTION_RETURN_OBJ (result);
6560 * mono_object_handle_isinst:
6562 * @klass: a pointer to a class
6563 * @error: set on error
6565 * Returns: @obj if @obj is derived from @klass or NULL if it isn't.
6566 * On failure returns NULL and sets @error.
6569 mono_object_handle_isinst (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
6574 mono_class_init (klass);
6576 if (mono_class_is_marshalbyref (klass) || mono_class_is_interface (klass)) {
6577 return mono_object_handle_isinst_mbyref (obj, klass, error);
6580 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6582 if (!MONO_HANDLE_IS_NULL (obj) && mono_class_is_assignable_from (klass, mono_handle_class (obj)))
6583 MONO_HANDLE_ASSIGN (result, obj);
6588 mono_object_isinst_mbyref (MonoObject *obj_raw, MonoClass *klass)
6590 MONO_REQ_GC_UNSAFE_MODE;
6592 HANDLE_FUNCTION_ENTER ();
6594 MONO_HANDLE_DCL (MonoObject, obj);
6595 MonoObjectHandle result = mono_object_handle_isinst_mbyref (obj, klass, &error);
6596 mono_error_cleanup (&error); /* FIXME better API that doesn't swallow the error */
6597 HANDLE_FUNCTION_RETURN_OBJ (result);
6601 mono_object_handle_isinst_mbyref (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
6605 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6607 if (MONO_HANDLE_IS_NULL (obj))
6610 MonoVTable *vt = MONO_HANDLE_GETVAL (obj, vtable);
6612 if (mono_class_is_interface (klass)) {
6613 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
6614 MONO_HANDLE_ASSIGN (result, obj);
6618 /* casting an array one of the invariant interfaces that must act as such */
6619 if (klass->is_array_special_interface) {
6620 if (mono_class_is_assignable_from (klass, vt->klass)) {
6621 MONO_HANDLE_ASSIGN (result, obj);
6626 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
6627 else if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, mono_handle_class (obj))) {
6628 MONO_HANDLE_ASSIGN (result, obj);
6632 MonoClass *oklass = vt->klass;
6633 if (mono_class_is_transparent_proxy (oklass)){
6634 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), remote_class);
6635 oklass = remote_class->proxy_class;
6638 mono_class_setup_supertypes (klass);
6639 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass)) {
6640 MONO_HANDLE_ASSIGN (result, obj);
6644 #ifndef DISABLE_REMOTING
6645 if (mono_class_is_transparent_proxy (vt->klass))
6647 MonoBoolean custom_type_info = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), custom_type_info);
6648 if (!custom_type_info)
6650 MonoDomain *domain = mono_domain_get ();
6651 MonoObjectHandle rp = MONO_HANDLE_NEW (MonoObject, NULL);
6652 MONO_HANDLE_GET (rp, MONO_HANDLE_CAST (MonoTransparentProxy, obj), rp);
6653 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
6654 MonoMethod *im = NULL;
6657 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
6659 mono_error_set_not_supported (error, "Linked away.");
6662 im = mono_object_handle_get_virtual_method (rp, im, error);
6667 MonoReflectionTypeHandle reftype = mono_type_get_object_handle (domain, &klass->byval_arg, error);
6671 pa [0] = MONO_HANDLE_RAW (reftype);
6672 pa [1] = MONO_HANDLE_RAW (obj);
6673 MonoObject *res = mono_runtime_invoke_checked (im, rp, pa, error);
6677 if (*(MonoBoolean *) mono_object_unbox(res)) {
6678 /* Update the vtable of the remote type, so it can safely cast to this new type */
6679 mono_upgrade_remote_class (domain, obj, klass, error);
6682 MONO_HANDLE_ASSIGN (result, obj);
6685 #endif /* DISABLE_REMOTING */
6691 * mono_object_castclass_mbyref:
6693 * @klass: a pointer to a class
6695 * Returns: @obj if @obj is derived from @klass, returns NULL otherwise.
6698 mono_object_castclass_mbyref (MonoObject *obj_raw, MonoClass *klass)
6700 MONO_REQ_GC_UNSAFE_MODE;
6701 HANDLE_FUNCTION_ENTER ();
6703 MONO_HANDLE_DCL (MonoObject, obj);
6704 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6705 if (MONO_HANDLE_IS_NULL (obj))
6707 MONO_HANDLE_ASSIGN (result, mono_object_handle_isinst_mbyref (obj, klass, &error));
6708 mono_error_cleanup (&error);
6710 HANDLE_FUNCTION_RETURN_OBJ (result);
6714 MonoDomain *orig_domain;
6720 str_lookup (MonoDomain *domain, gpointer user_data)
6722 MONO_REQ_GC_UNSAFE_MODE;
6724 LDStrInfo *info = (LDStrInfo *)user_data;
6725 if (info->res || domain == info->orig_domain)
6727 info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
6731 mono_string_get_pinned (MonoString *str, MonoError *error)
6733 MONO_REQ_GC_UNSAFE_MODE;
6737 /* We only need to make a pinned version of a string if this is a moving GC */
6738 if (!mono_gc_is_moving ())
6742 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
6743 news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
6745 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
6746 news->length = mono_string_length (str);
6748 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6754 mono_string_is_interned_lookup (MonoString *str, int insert, MonoError *error)
6756 MONO_REQ_GC_UNSAFE_MODE;
6758 MonoGHashTable *ldstr_table;
6759 MonoString *s, *res;
6764 domain = ((MonoObject *)str)->vtable->domain;
6765 ldstr_table = domain->ldstr_table;
6767 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6773 /* Allocate outside the lock */
6775 s = mono_string_get_pinned (str, error);
6776 return_val_if_nok (error, NULL);
6779 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6784 mono_g_hash_table_insert (ldstr_table, s, s);
6789 LDStrInfo ldstr_info;
6790 ldstr_info.orig_domain = domain;
6791 ldstr_info.ins = str;
6792 ldstr_info.res = NULL;
6794 mono_domain_foreach (str_lookup, &ldstr_info);
6795 if (ldstr_info.res) {
6797 * the string was already interned in some other domain:
6798 * intern it in the current one as well.
6800 mono_g_hash_table_insert (ldstr_table, str, str);
6810 * mono_string_is_interned:
6811 * @o: String to probe
6813 * Returns whether the string has been interned.
6816 mono_string_is_interned (MonoString *o)
6819 MonoString *result = mono_string_is_interned_lookup (o, FALSE, &error);
6820 /* This function does not fail. */
6821 mono_error_assert_ok (&error);
6826 * mono_string_intern:
6827 * @o: String to intern
6829 * Interns the string passed.
6830 * Returns: The interned string.
6833 mono_string_intern (MonoString *str)
6836 MonoString *result = mono_string_intern_checked (str, &error);
6837 mono_error_assert_ok (&error);
6842 * mono_string_intern_checked:
6843 * @o: String to intern
6844 * @error: set on error.
6846 * Interns the string passed.
6847 * Returns: The interned string. On failure returns NULL and sets @error
6850 mono_string_intern_checked (MonoString *str, MonoError *error)
6852 MONO_REQ_GC_UNSAFE_MODE;
6856 return mono_string_is_interned_lookup (str, TRUE, error);
6861 * @domain: the domain where the string will be used.
6862 * @image: a metadata context
6863 * @idx: index into the user string table.
6865 * Implementation for the ldstr opcode.
6866 * Returns: a loaded string from the @image/@idx combination.
6869 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
6872 MonoString *result = mono_ldstr_checked (domain, image, idx, &error);
6873 mono_error_cleanup (&error);
6878 * mono_ldstr_checked:
6879 * @domain: the domain where the string will be used.
6880 * @image: a metadata context
6881 * @idx: index into the user string table.
6882 * @error: set on error.
6884 * Implementation for the ldstr opcode.
6885 * Returns: a loaded string from the @image/@idx combination.
6886 * On failure returns NULL and sets @error.
6889 mono_ldstr_checked (MonoDomain *domain, MonoImage *image, guint32 idx, MonoError *error)
6891 MONO_REQ_GC_UNSAFE_MODE;
6894 if (image->dynamic) {
6895 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL, error);
6898 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6899 return NULL; /*FIXME we should probably be raising an exception here*/
6900 MonoString *str = mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx), error);
6906 * mono_ldstr_metadata_sig
6907 * @domain: the domain for the string
6908 * @sig: the signature of a metadata string
6909 * @error: set on error
6911 * Returns: a MonoString for a string stored in the metadata. On
6912 * failure returns NULL and sets @error.
6915 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error)
6917 MONO_REQ_GC_UNSAFE_MODE;
6920 const char *str = sig;
6921 MonoString *o, *interned;
6924 len2 = mono_metadata_decode_blob_size (str, &str);
6927 o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, error);
6928 return_val_if_nok (error, NULL);
6929 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
6932 guint16 *p2 = (guint16*)mono_string_chars (o);
6933 for (i = 0; i < len2; ++i) {
6934 *p2 = GUINT16_FROM_LE (*p2);
6940 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6943 return interned; /* o will get garbage collected */
6945 o = mono_string_get_pinned (o, error);
6948 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6950 mono_g_hash_table_insert (domain->ldstr_table, o, o);
6962 * Same as mono_ldstr, but return a NULL terminated utf8 string instead
6966 mono_ldstr_utf8 (MonoImage *image, guint32 idx, MonoError *error)
6972 GError *gerror = NULL;
6976 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6977 return NULL; /*FIXME we should probably be raising an exception here*/
6978 str = mono_metadata_user_string (image, idx);
6980 len2 = mono_metadata_decode_blob_size (str, &str);
6983 as = g_utf16_to_utf8 ((guint16*)str, len2, NULL, &written, &gerror);
6985 mono_error_set_argument (error, "string", "%s", gerror->message);
6986 g_error_free (gerror);
6989 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6990 if (len2 > written) {
6991 /* allocate the total length and copy the part of the string that has been converted */
6992 char *as2 = (char *)g_malloc0 (len2);
6993 memcpy (as2, as, written);
7002 * mono_string_to_utf8:
7003 * @s: a System.String
7005 * Returns the UTF8 representation for @s.
7006 * The resulting buffer needs to be freed with mono_free().
7008 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
7011 mono_string_to_utf8 (MonoString *s)
7013 MONO_REQ_GC_UNSAFE_MODE;
7016 char *result = mono_string_to_utf8_checked (s, &error);
7018 if (!is_ok (&error)) {
7019 mono_error_cleanup (&error);
7026 * mono_string_to_utf8_checked:
7027 * @s: a System.String
7028 * @error: a MonoError.
7030 * Converts a MonoString to its UTF8 representation. May fail; check
7031 * @error to determine whether the conversion was successful.
7032 * The resulting buffer should be freed with mono_free().
7035 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
7037 MONO_REQ_GC_UNSAFE_MODE;
7041 GError *gerror = NULL;
7049 return g_strdup ("");
7051 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
7053 mono_error_set_argument (error, "string", "%s", gerror->message);
7054 g_error_free (gerror);
7057 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
7058 if (s->length > written) {
7059 /* allocate the total length and copy the part of the string that has been converted */
7060 char *as2 = (char *)g_malloc0 (s->length);
7061 memcpy (as2, as, written);
7070 mono_string_handle_to_utf8 (MonoStringHandle s, MonoError *error)
7072 return mono_string_to_utf8_checked (MONO_HANDLE_RAW (s), error);
7076 * mono_string_to_utf8_ignore:
7079 * Converts a MonoString to its UTF8 representation. Will ignore
7080 * invalid surrogate pairs.
7081 * The resulting buffer should be freed with mono_free().
7085 mono_string_to_utf8_ignore (MonoString *s)
7087 MONO_REQ_GC_UNSAFE_MODE;
7096 return g_strdup ("");
7098 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
7100 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
7101 if (s->length > written) {
7102 /* allocate the total length and copy the part of the string that has been converted */
7103 char *as2 = (char *)g_malloc0 (s->length);
7104 memcpy (as2, as, written);
7113 * mono_string_to_utf8_image_ignore:
7114 * @s: a System.String
7116 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
7119 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
7121 MONO_REQ_GC_UNSAFE_MODE;
7123 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
7127 * mono_string_to_utf8_mp_ignore:
7128 * @s: a System.String
7130 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
7133 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
7135 MONO_REQ_GC_UNSAFE_MODE;
7137 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
7142 * mono_string_to_utf16:
7145 * Return an null-terminated array of the utf-16 chars
7146 * contained in @s. The result must be freed with g_free().
7147 * This is a temporary helper until our string implementation
7148 * is reworked to always include the null terminating char.
7151 mono_string_to_utf16 (MonoString *s)
7153 MONO_REQ_GC_UNSAFE_MODE;
7160 as = (char *)g_malloc ((s->length * 2) + 2);
7161 as [(s->length * 2)] = '\0';
7162 as [(s->length * 2) + 1] = '\0';
7165 return (gunichar2 *)(as);
7168 memcpy (as, mono_string_chars(s), s->length * 2);
7169 return (gunichar2 *)(as);
7173 * mono_string_to_utf32:
7176 * Return an null-terminated array of the UTF-32 (UCS-4) chars
7177 * contained in @s. The result must be freed with g_free().
7180 mono_string_to_utf32 (MonoString *s)
7182 MONO_REQ_GC_UNSAFE_MODE;
7184 mono_unichar4 *utf32_output = NULL;
7185 GError *error = NULL;
7186 glong items_written;
7191 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
7194 g_error_free (error);
7196 return utf32_output;
7200 * mono_string_from_utf16:
7201 * @data: the UTF16 string (LPWSTR) to convert
7203 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
7205 * Returns: a MonoString.
7208 mono_string_from_utf16 (gunichar2 *data)
7211 MonoString *result = mono_string_from_utf16_checked (data, &error);
7212 mono_error_cleanup (&error);
7217 * mono_string_from_utf16_checked:
7218 * @data: the UTF16 string (LPWSTR) to convert
7219 * @error: set on error
7221 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
7223 * Returns: a MonoString. On failure sets @error and returns NULL.
7226 mono_string_from_utf16_checked (gunichar2 *data, MonoError *error)
7229 MONO_REQ_GC_UNSAFE_MODE;
7232 MonoDomain *domain = mono_domain_get ();
7238 while (data [len]) len++;
7240 return mono_string_new_utf16_checked (domain, data, len, error);
7244 * mono_string_from_utf32:
7245 * @data: the UTF32 string (LPWSTR) to convert
7247 * Converts a UTF32 (UCS-4)to a MonoString.
7249 * Returns: a MonoString.
7252 mono_string_from_utf32 (mono_unichar4 *data)
7255 MonoString *result = mono_string_from_utf32_checked (data, &error);
7256 mono_error_cleanup (&error);
7261 * mono_string_from_utf32_checked:
7262 * @data: the UTF32 string (LPWSTR) to convert
7263 * @error: set on error
7265 * Converts a UTF32 (UCS-4)to a MonoString.
7267 * Returns: a MonoString. On failure returns NULL and sets @error.
7270 mono_string_from_utf32_checked (mono_unichar4 *data, MonoError *error)
7272 MONO_REQ_GC_UNSAFE_MODE;
7275 MonoString* result = NULL;
7276 mono_unichar2 *utf16_output = NULL;
7277 GError *gerror = NULL;
7278 glong items_written;
7284 while (data [len]) len++;
7286 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &gerror);
7289 g_error_free (gerror);
7291 result = mono_string_from_utf16_checked (utf16_output, error);
7292 g_free (utf16_output);
7297 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
7299 MONO_REQ_GC_UNSAFE_MODE;
7306 r = mono_string_to_utf8_ignore (s);
7308 r = mono_string_to_utf8_checked (s, error);
7309 if (!mono_error_ok (error))
7316 len = strlen (r) + 1;
7318 mp_s = (char *)mono_mempool_alloc (mp, len);
7320 mp_s = (char *)mono_image_alloc (image, len);
7322 memcpy (mp_s, r, len);
7330 * mono_string_to_utf8_image:
7331 * @s: a System.String
7333 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
7336 mono_string_to_utf8_image (MonoImage *image, MonoStringHandle s, MonoError *error)
7338 MONO_REQ_GC_UNSAFE_MODE;
7340 return mono_string_to_utf8_internal (NULL, image, MONO_HANDLE_RAW (s), FALSE, error); /* FIXME pin the string */
7344 * mono_string_to_utf8_mp:
7345 * @s: a System.String
7347 * Same as mono_string_to_utf8, but allocate the string from a mempool.
7350 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
7352 MONO_REQ_GC_UNSAFE_MODE;
7354 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
7358 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
7361 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
7363 eh_callbacks = *cbs;
7366 MonoRuntimeExceptionHandlingCallbacks *
7367 mono_get_eh_callbacks (void)
7369 return &eh_callbacks;
7373 * mono_raise_exception:
7374 * @ex: exception object
7376 * Signal the runtime that the exception @ex has been raised in unmanaged code.
7379 mono_raise_exception (MonoException *ex)
7381 MONO_REQ_GC_UNSAFE_MODE;
7384 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
7385 * that will cause gcc to omit the function epilog, causing problems when
7386 * the JIT tries to walk the stack, since the return address on the stack
7387 * will point into the next function in the executable, not this one.
7389 eh_callbacks.mono_raise_exception (ex);
7393 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
7395 MONO_REQ_GC_UNSAFE_MODE;
7397 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
7401 * mono_wait_handle_new:
7402 * @domain: Domain where the object will be created
7403 * @handle: Handle for the wait handle
7404 * @error: set on error.
7406 * Returns: A new MonoWaitHandle created in the given domain for the
7407 * given handle. On failure returns NULL and sets @rror.
7410 mono_wait_handle_new (MonoDomain *domain, HANDLE handle, MonoError *error)
7412 MONO_REQ_GC_UNSAFE_MODE;
7414 MonoWaitHandle *res;
7415 gpointer params [1];
7416 static MonoMethod *handle_set;
7419 res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, error);
7420 return_val_if_nok (error, NULL);
7422 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
7424 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
7426 params [0] = &handle;
7428 mono_runtime_invoke_checked (handle_set, res, params, error);
7433 mono_wait_handle_get_handle (MonoWaitHandle *handle)
7435 MONO_REQ_GC_UNSAFE_MODE;
7437 static MonoClassField *f_safe_handle = NULL;
7440 if (!f_safe_handle) {
7441 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safeWaitHandle");
7442 g_assert (f_safe_handle);
7445 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
7451 mono_runtime_capture_context (MonoDomain *domain, MonoError *error)
7453 MONO_REQ_GC_UNSAFE_MODE;
7455 RuntimeInvokeFunction runtime_invoke;
7459 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
7460 MonoMethod *method = mono_get_context_capture_method ();
7461 MonoMethod *wrapper;
7464 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
7465 domain->capture_context_runtime_invoke = mono_compile_method_checked (wrapper, error);
7466 return_val_if_nok (error, NULL);
7467 domain->capture_context_method = mono_compile_method_checked (method, error);
7468 return_val_if_nok (error, NULL);
7471 runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
7473 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
7476 * mono_async_result_new:
7477 * @domain:domain where the object will be created.
7478 * @handle: wait handle.
7479 * @state: state to pass to AsyncResult
7480 * @data: C closure data.
7481 * @error: set on error.
7483 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
7484 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
7485 * On failure returns NULL and sets @error.
7489 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data, MonoError *error)
7491 MONO_REQ_GC_UNSAFE_MODE;
7494 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, error);
7495 return_val_if_nok (error, NULL);
7496 MonoObject *context = mono_runtime_capture_context (domain, error);
7497 return_val_if_nok (error, NULL);
7498 /* we must capture the execution context from the original thread */
7500 MONO_OBJECT_SETREF (res, execution_context, context);
7501 /* note: result may be null if the flow is suppressed */
7504 res->data = (void **)data;
7505 MONO_OBJECT_SETREF (res, object_data, object_data);
7506 MONO_OBJECT_SETREF (res, async_state, state);
7507 MonoWaitHandle *wait_handle = mono_wait_handle_new (domain, handle, error);
7508 return_val_if_nok (error, NULL);
7510 MONO_OBJECT_SETREF (res, handle, (MonoObject *) wait_handle);
7512 res->sync_completed = FALSE;
7513 res->completed = FALSE;
7519 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
7521 MONO_REQ_GC_UNSAFE_MODE;
7528 g_assert (ares->async_delegate);
7530 ac = (MonoAsyncCall*) ares->object_data;
7532 res = mono_runtime_delegate_invoke_checked (ares->async_delegate, (void**) &ares->async_state, &error);
7533 if (mono_error_set_pending_exception (&error))
7536 gpointer wait_event = NULL;
7538 ac->msg->exc = NULL;
7540 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args, &error);
7542 /* The exit side of the invoke must not be aborted as it would leave the runtime in an undefined state */
7543 mono_threads_begin_abort_protected_block ();
7545 if (!ac->msg->exc) {
7546 MonoException *ex = mono_error_convert_to_exception (&error);
7547 ac->msg->exc = (MonoObject *)ex;
7549 mono_error_cleanup (&error);
7552 MONO_OBJECT_SETREF (ac, res, res);
7554 mono_monitor_enter ((MonoObject*) ares);
7555 ares->completed = 1;
7557 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
7558 mono_monitor_exit ((MonoObject*) ares);
7560 if (wait_event != NULL)
7561 mono_w32event_set (wait_event);
7563 error_init (&error); //the else branch would leave it in an undefined state
7565 mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
7567 mono_threads_end_abort_protected_block ();
7569 if (mono_error_set_pending_exception (&error))
7577 mono_message_init (MonoDomain *domain,
7578 MonoMethodMessage *this_obj,
7579 MonoReflectionMethod *method,
7580 MonoArray *out_args,
7583 MONO_REQ_GC_UNSAFE_MODE;
7585 static MonoMethod *init_message_method = NULL;
7587 if (!init_message_method) {
7588 init_message_method = mono_class_get_method_from_name (mono_defaults.mono_method_message_class, "InitMessage", 2);
7589 g_assert (init_message_method != NULL);
7593 /* FIXME set domain instead? */
7594 g_assert (domain == mono_domain_get ());
7601 mono_runtime_invoke_checked (init_message_method, this_obj, args, error);
7602 return is_ok (error);
7605 #ifndef DISABLE_REMOTING
7607 * mono_remoting_invoke:
7608 * @real_proxy: pointer to a RealProxy object
7609 * @msg: The MonoMethodMessage to execute
7610 * @exc: used to store exceptions
7611 * @out_args: used to store output arguments
7613 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
7614 * IMessage interface and it is not trivial to extract results from there. So
7615 * we call an helper method PrivateInvoke instead of calling
7616 * RealProxy::Invoke() directly.
7618 * Returns: the result object.
7621 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, MonoObject **exc, MonoArray **out_args, MonoError *error)
7623 MONO_REQ_GC_UNSAFE_MODE;
7626 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
7633 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
7636 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
7638 mono_error_set_not_supported (error, "Linked away.");
7641 real_proxy->vtable->domain->private_invoke_method = im;
7644 pa [0] = real_proxy;
7649 o = mono_runtime_try_invoke (im, NULL, pa, exc, error);
7650 return_val_if_nok (error, NULL);
7657 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
7658 MonoObject **exc, MonoArray **out_args, MonoError *error)
7660 MONO_REQ_GC_UNSAFE_MODE;
7662 static MonoClass *object_array_klass;
7667 MonoMethodSignature *sig;
7669 int i, j, outarg_count = 0;
7671 #ifndef DISABLE_REMOTING
7672 if (target && mono_object_is_transparent_proxy (target)) {
7673 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
7674 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7675 target = tp->rp->unwrapped_server;
7677 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args, error);
7682 domain = mono_domain_get ();
7683 method = msg->method->method;
7684 sig = mono_method_signature (method);
7686 for (i = 0; i < sig->param_count; i++) {
7687 if (sig->params [i]->byref)
7691 if (!object_array_klass) {
7694 klass = mono_array_class_get (mono_defaults.object_class, 1);
7697 mono_memory_barrier ();
7698 object_array_klass = klass;
7701 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, error);
7702 return_val_if_nok (error, NULL);
7704 mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
7707 MonoObject *ret = mono_runtime_try_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc, error);
7708 return_val_if_nok (error, NULL);
7710 for (i = 0, j = 0; i < sig->param_count; i++) {
7711 if (sig->params [i]->byref) {
7713 arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
7714 mono_array_setref (*out_args, j, arg);
7723 * prepare_to_string_method:
7725 * @target: Set to @obj or unboxed value if a valuetype
7727 * Returns: the ToString override for @obj. If @obj is a valuetype, @target is unboxed otherwise it's @obj.
7730 prepare_to_string_method (MonoObject *obj, void **target)
7732 MONO_REQ_GC_UNSAFE_MODE;
7734 static MonoMethod *to_string = NULL;
7742 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
7744 method = mono_object_get_virtual_method (obj, to_string);
7746 // Unbox value type if needed
7747 if (mono_class_is_valuetype (mono_method_get_class (method))) {
7748 *target = mono_object_unbox (obj);
7754 * mono_object_to_string:
7756 * @exc: Any exception thrown by ToString (). May be NULL.
7758 * Returns: the result of calling ToString () on an object.
7761 mono_object_to_string (MonoObject *obj, MonoObject **exc)
7764 MonoString *s = NULL;
7766 MonoMethod *method = prepare_to_string_method (obj, &target);
7768 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
7769 if (*exc == NULL && !mono_error_ok (&error))
7770 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
7772 mono_error_cleanup (&error);
7774 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
7775 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
7782 * mono_object_to_string_checked:
7784 * @error: Set on error.
7786 * Returns: the result of calling ToString () on an object. If the
7787 * method cannot be invoked or if it raises an exception, sets @error
7791 mono_object_to_string_checked (MonoObject *obj, MonoError *error)
7795 MonoMethod *method = prepare_to_string_method (obj, &target);
7796 return (MonoString*) mono_runtime_invoke_checked (method, target, NULL, error);
7800 * mono_object_try_to_string:
7802 * @exc: Any exception thrown by ToString (). Must not be NULL.
7803 * @error: Set if method cannot be invoked.
7805 * Returns: the result of calling ToString () on an object. If the
7806 * method cannot be invoked sets @error, if it raises an exception sets @exc,
7810 mono_object_try_to_string (MonoObject *obj, MonoObject **exc, MonoError *error)
7815 MonoMethod *method = prepare_to_string_method (obj, &target);
7816 return (MonoString*) mono_runtime_try_invoke (method, target, NULL, exc, error);
7822 get_native_backtrace (MonoException *exc_raw)
7824 HANDLE_FUNCTION_ENTER ();
7825 MONO_HANDLE_DCL(MonoException, exc);
7826 char * trace = mono_exception_handle_get_native_backtrace (exc);
7827 HANDLE_FUNCTION_RETURN_VAL (trace);
7831 * mono_print_unhandled_exception:
7832 * @exc: The exception
7834 * Prints the unhandled exception.
7837 mono_print_unhandled_exception (MonoObject *exc)
7839 MONO_REQ_GC_UNSAFE_MODE;
7842 char *message = (char*)"";
7843 gboolean free_message = FALSE;
7846 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
7847 message = g_strdup ("OutOfMemoryException");
7848 free_message = TRUE;
7849 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
7850 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
7851 free_message = TRUE;
7854 if (((MonoException*)exc)->native_trace_ips) {
7855 message = get_native_backtrace ((MonoException*)exc);
7856 free_message = TRUE;
7858 MonoObject *other_exc = NULL;
7859 str = mono_object_try_to_string (exc, &other_exc, &error);
7860 if (other_exc == NULL && !is_ok (&error))
7861 other_exc = (MonoObject*)mono_error_convert_to_exception (&error);
7863 mono_error_cleanup (&error);
7865 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
7866 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
7868 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
7869 original_backtrace, nested_backtrace);
7871 g_free (original_backtrace);
7872 g_free (nested_backtrace);
7873 free_message = TRUE;
7875 message = mono_string_to_utf8_checked (str, &error);
7876 if (!mono_error_ok (&error)) {
7877 mono_error_cleanup (&error);
7878 message = (char *) "";
7880 free_message = TRUE;
7887 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
7888 * exc->vtable->klass->name, message);
7890 g_printerr ("\nUnhandled Exception:\n%s\n", message);
7897 * mono_delegate_ctor_with_method:
7898 * @this: pointer to an uninitialized delegate object
7899 * @target: target object
7900 * @addr: pointer to native code
7902 * @error: set on error.
7904 * Initialize a delegate and sets a specific method, not the one
7905 * associated with addr. This is useful when sharing generic code.
7906 * In that case addr will most probably not be associated with the
7907 * correct instantiation of the method.
7908 * On failure returns FALSE and sets @error.
7911 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method, MonoError *error)
7913 MONO_REQ_GC_UNSAFE_MODE;
7916 MonoDelegate *delegate = (MonoDelegate *)this_obj;
7918 g_assert (this_obj);
7921 g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
7924 delegate->method = method;
7926 mono_stats.delegate_creations++;
7928 #ifndef DISABLE_REMOTING
7929 if (target && mono_object_is_transparent_proxy (target)) {
7931 method = mono_marshal_get_remoting_invoke (method);
7932 #ifdef ENABLE_INTERPRETER
7933 g_error ("need RuntimeMethod in method_ptr when using interpreter");
7935 delegate->method_ptr = mono_compile_method_checked (method, error);
7936 return_val_if_nok (error, FALSE);
7937 MONO_OBJECT_SETREF (delegate, target, target);
7941 delegate->method_ptr = addr;
7942 MONO_OBJECT_SETREF (delegate, target, target);
7945 delegate->invoke_impl = callbacks.create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
7946 if (callbacks.init_delegate)
7947 callbacks.init_delegate (delegate);
7952 * mono_delegate_ctor:
7953 * @this: pointer to an uninitialized delegate object
7954 * @target: target object
7955 * @addr: pointer to native code
7956 * @error: set on error.
7958 * This is used to initialize a delegate.
7959 * On failure returns FALSE and sets @error.
7962 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoError *error)
7964 MONO_REQ_GC_UNSAFE_MODE;
7967 MonoDomain *domain = mono_domain_get ();
7969 MonoMethod *method = NULL;
7973 ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
7975 if (!ji && domain != mono_get_root_domain ())
7976 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
7978 method = mono_jit_info_get_method (ji);
7979 g_assert (!mono_class_is_gtd (method->klass));
7982 return mono_delegate_ctor_with_method (this_obj, target, addr, method, error);
7986 * mono_method_call_message_new:
7987 * @method: method to encapsulate
7988 * @params: parameters to the method
7989 * @invoke: optional, delegate invoke.
7990 * @cb: async callback delegate.
7991 * @state: state passed to the async callback.
7992 * @error: set on error.
7994 * Translates arguments pointers into a MonoMethodMessage.
7995 * On failure returns NULL and sets @error.
7998 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
7999 MonoDelegate **cb, MonoObject **state, MonoError *error)
8001 MONO_REQ_GC_UNSAFE_MODE;
8005 MonoDomain *domain = mono_domain_get ();
8006 MonoMethodSignature *sig = mono_method_signature (method);
8007 MonoMethodMessage *msg;
8010 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8011 return_val_if_nok (error, NULL);
8014 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, error);
8015 return_val_if_nok (error, NULL);
8016 mono_message_init (domain, msg, rm, NULL, error);
8017 return_val_if_nok (error, NULL);
8018 count = sig->param_count - 2;
8020 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
8021 return_val_if_nok (error, NULL);
8022 mono_message_init (domain, msg, rm, NULL, error);
8023 return_val_if_nok (error, NULL);
8024 count = sig->param_count;
8027 for (i = 0; i < count; i++) {
8032 if (sig->params [i]->byref)
8033 vpos = *((gpointer *)params [i]);
8037 klass = mono_class_from_mono_type (sig->params [i]);
8039 if (klass->valuetype) {
8040 arg = mono_value_box_checked (domain, klass, vpos, error);
8041 return_val_if_nok (error, NULL);
8043 arg = *((MonoObject **)vpos);
8045 mono_array_setref (msg->args, i, arg);
8048 if (cb != NULL && state != NULL) {
8049 *cb = *((MonoDelegate **)params [i]);
8051 *state = *((MonoObject **)params [i]);
8058 * mono_method_return_message_restore:
8060 * Restore results from message based processing back to arguments pointers
8063 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args, MonoError *error)
8065 MONO_REQ_GC_UNSAFE_MODE;
8069 MonoMethodSignature *sig = mono_method_signature (method);
8070 int i, j, type, size, out_len;
8072 if (out_args == NULL)
8074 out_len = mono_array_length (out_args);
8078 for (i = 0, j = 0; i < sig->param_count; i++) {
8079 MonoType *pt = sig->params [i];
8084 mono_error_set_execution_engine (error, "The proxy call returned an incorrect number of output arguments");
8088 arg = (char *)mono_array_get (out_args, gpointer, j);
8091 g_assert (type != MONO_TYPE_VOID);
8093 if (MONO_TYPE_IS_REFERENCE (pt)) {
8094 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
8097 MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
8098 size = mono_class_value_size (klass, NULL);
8099 if (klass->has_references)
8100 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
8102 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
8104 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
8105 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
8114 #ifndef DISABLE_REMOTING
8117 * mono_load_remote_field:
8118 * @this: pointer to an object
8119 * @klass: klass of the object containing @field
8120 * @field: the field to load
8121 * @res: a storage to store the result
8123 * This method is called by the runtime on attempts to load fields of
8124 * transparent proxy objects. @this points to such TP, @klass is the class of
8125 * the object containing @field. @res is a storage location which can be
8126 * used to store the result.
8128 * Returns: an address pointing to the value of field.
8131 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
8134 gpointer result = mono_load_remote_field_checked (this_obj, klass, field, res, &error);
8135 mono_error_cleanup (&error);
8140 * mono_load_remote_field_checked:
8141 * @this: pointer to an object
8142 * @klass: klass of the object containing @field
8143 * @field: the field to load
8144 * @res: a storage to store the result
8145 * @error: set on error
8147 * This method is called by the runtime on attempts to load fields of
8148 * transparent proxy objects. @this points to such TP, @klass is the class of
8149 * the object containing @field. @res is a storage location which can be
8150 * used to store the result.
8152 * Returns: an address pointing to the value of field. On failure returns NULL and sets @error.
8155 mono_load_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res, MonoError *error)
8157 MONO_REQ_GC_UNSAFE_MODE;
8159 static MonoMethod *getter = NULL;
8163 MonoDomain *domain = mono_domain_get ();
8164 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8165 MonoClass *field_class;
8166 MonoMethodMessage *msg;
8167 MonoArray *out_args;
8171 g_assert (mono_object_is_transparent_proxy (this_obj));
8172 g_assert (res != NULL);
8174 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8175 mono_field_get_value (tp->rp->unwrapped_server, field, res);
8180 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
8182 mono_error_set_not_supported (error, "Linked away.");
8187 field_class = mono_class_from_mono_type (field->type);
8189 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8190 return_val_if_nok (error, NULL);
8191 out_args = mono_array_new_checked (domain, mono_defaults.object_class, 1, error);
8192 return_val_if_nok (error, NULL);
8193 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, error);
8194 return_val_if_nok (error, NULL);
8195 mono_message_init (domain, msg, rm, out_args, error);
8196 return_val_if_nok (error, NULL);
8198 full_name = mono_type_get_full_name (klass);
8199 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
8200 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
8203 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8204 return_val_if_nok (error, NULL);
8207 mono_error_set_exception_instance (error, (MonoException *)exc);
8211 if (mono_array_length (out_args) == 0)
8214 mono_gc_wbarrier_generic_store (res, mono_array_get (out_args, MonoObject *, 0));
8216 if (field_class->valuetype) {
8217 return ((char *)*res) + sizeof (MonoObject);
8223 * mono_load_remote_field_new:
8228 * Missing documentation.
8231 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
8235 MonoObject *result = mono_load_remote_field_new_checked (this_obj, klass, field, &error);
8236 mono_error_cleanup (&error);
8241 * mono_load_remote_field_new_checked:
8242 * @this: pointer to an object
8243 * @klass: klass of the object containing @field
8244 * @field: the field to load
8245 * @error: set on error.
8247 * This method is called by the runtime on attempts to load fields of
8248 * transparent proxy objects. @this points to such TP, @klass is the class of
8249 * the object containing @field.
8251 * Returns: a freshly allocated object containing the value of the field. On failure returns NULL and sets @error.
8254 mono_load_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoError *error)
8256 MONO_REQ_GC_UNSAFE_MODE;
8260 static MonoMethod *tp_load = NULL;
8262 g_assert (mono_object_is_transparent_proxy (this_obj));
8265 tp_load = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "LoadRemoteFieldNew", -1);
8267 mono_error_set_not_supported (error, "Linked away.");
8272 /* MonoType *type = mono_class_get_type (klass); */
8278 return mono_runtime_invoke_checked (tp_load, this_obj, args, error);
8282 * mono_store_remote_field:
8283 * @this_obj: pointer to an object
8284 * @klass: klass of the object containing @field
8285 * @field: the field to load
8286 * @val: the value/object to store
8288 * This method is called by the runtime on attempts to store fields of
8289 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
8290 * the object containing @field. @val is the new value to store in @field.
8293 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
8296 (void) mono_store_remote_field_checked (this_obj, klass, field, val, &error);
8297 mono_error_cleanup (&error);
8301 * mono_store_remote_field_checked:
8302 * @this_obj: pointer to an object
8303 * @klass: klass of the object containing @field
8304 * @field: the field to load
8305 * @val: the value/object to store
8306 * @error: set on error
8308 * This method is called by the runtime on attempts to store fields of
8309 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
8310 * the object containing @field. @val is the new value to store in @field.
8312 * Returns: on success returns TRUE, on failure returns FALSE and sets @error.
8315 mono_store_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val, MonoError *error)
8318 MONO_REQ_GC_UNSAFE_MODE;
8322 MonoDomain *domain = mono_domain_get ();
8323 MonoClass *field_class;
8326 g_assert (mono_object_is_transparent_proxy (this_obj));
8328 field_class = mono_class_from_mono_type (field->type);
8330 if (field_class->valuetype) {
8331 arg = mono_value_box_checked (domain, field_class, val, error);
8332 return_val_if_nok (error, FALSE);
8334 arg = *((MonoObject**)val);
8337 return mono_store_remote_field_new_checked (this_obj, klass, field, arg, error);
8341 * mono_store_remote_field_new:
8347 * Missing documentation
8350 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
8353 (void) mono_store_remote_field_new_checked (this_obj, klass, field, arg, &error);
8354 mono_error_cleanup (&error);
8358 * mono_store_remote_field_new_checked:
8365 * Missing documentation
8368 mono_store_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg, MonoError *error)
8370 MONO_REQ_GC_UNSAFE_MODE;
8372 static MonoMethod *tp_store = NULL;
8376 g_assert (mono_object_is_transparent_proxy (this_obj));
8379 tp_store = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "StoreRemoteField", -1);
8381 mono_error_set_not_supported (error, "Linked away.");
8391 mono_runtime_invoke_checked (tp_store, this_obj, args, error);
8392 return is_ok (error);
8397 * mono_create_ftnptr:
8399 * Given a function address, create a function descriptor for it.
8400 * This is only needed on some platforms.
8403 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
8405 return callbacks.create_ftnptr (domain, addr);
8409 * mono_get_addr_from_ftnptr:
8411 * Given a pointer to a function descriptor, return the function address.
8412 * This is only needed on some platforms.
8415 mono_get_addr_from_ftnptr (gpointer descr)
8417 return callbacks.get_addr_from_ftnptr (descr);
8421 * mono_string_chars:
8424 * Returns a pointer to the UCS16 characters stored in the MonoString
8427 mono_string_chars (MonoString *s)
8429 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
8435 * mono_string_length:
8438 * Returns the lenght in characters of the string
8441 mono_string_length (MonoString *s)
8443 MONO_REQ_GC_UNSAFE_MODE;
8449 * mono_string_handle_length:
8452 * Returns the lenght in characters of the string
8455 mono_string_handle_length (MonoStringHandle s)
8457 MONO_REQ_GC_UNSAFE_MODE;
8459 return MONO_HANDLE_GETVAL (s, length);
8464 * mono_array_length:
8465 * @array: a MonoArray*
8467 * Returns the total number of elements in the array. This works for
8468 * both vectors and multidimensional arrays.
8471 mono_array_length (MonoArray *array)
8473 MONO_REQ_GC_UNSAFE_MODE;
8475 return array->max_length;
8479 * mono_array_addr_with_size:
8480 * @array: a MonoArray*
8481 * @size: size of the array elements
8482 * @idx: index into the array
8484 * Use this function to obtain the address for the @idx item on the
8485 * @array containing elements of size @size.
8487 * This method performs no bounds checking or type checking.
8489 * Returns the address of the @idx element in the array.
8492 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
8494 MONO_REQ_GC_UNSAFE_MODE;
8496 return ((char*)(array)->vector) + size * idx;
8501 mono_glist_to_array (GList *list, MonoClass *eclass, MonoError *error)
8503 MonoDomain *domain = mono_domain_get ();
8511 len = g_list_length (list);
8512 res = mono_array_new_checked (domain, eclass, len, error);
8513 return_val_if_nok (error, NULL);
8515 for (i = 0; list; list = list->next, i++)
8516 mono_array_set (res, gpointer, i, list->data);
8523 * The following section is purely to declare prototypes and
8524 * document the API, as these C files are processed by our
8530 * @array: array to alter
8531 * @element_type: A C type name, this macro will use the sizeof(type) to determine the element size
8532 * @index: index into the array
8533 * @value: value to set
8535 * Value Type version: This sets the @index's element of the @array
8536 * with elements of size sizeof(type) to the provided @value.
8538 * This macro does not attempt to perform type checking or bounds checking.
8540 * Use this to set value types in a `MonoArray`.
8542 void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
8547 * mono_array_setref:
8548 * @array: array to alter
8549 * @index: index into the array
8550 * @value: value to set
8552 * Reference Type version: This sets the @index's element of the
8553 * @array with elements of size sizeof(type) to the provided @value.
8555 * This macro does not attempt to perform type checking or bounds checking.
8557 * Use this to reference types in a `MonoArray`.
8559 void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
8565 * @array: array on which to operate on
8566 * @element_type: C element type (example: MonoString *, int, MonoObject *)
8567 * @index: index into the array
8569 * Use this macro to retrieve the @index element of an @array and
8570 * extract the value assuming that the elements of the array match
8571 * the provided type value.
8573 * This method can be used with both arrays holding value types and
8574 * reference types. For reference types, the @type parameter should
8575 * be a `MonoObject*` or any subclass of it, like `MonoString*`.
8577 * This macro does not attempt to perform type checking or bounds checking.
8579 * Returns: The element at the @index position in the @array.
8581 Type mono_array_get (MonoArray *array, Type element_type, uintptr_t index)