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/mono-debug-debugger.h"
40 #include <mono/metadata/verify-internals.h>
41 #include <mono/metadata/reflection-internals.h>
42 #include <mono/metadata/w32event.h>
43 #include <mono/utils/strenc.h>
44 #include <mono/utils/mono-counters.h>
45 #include <mono/utils/mono-error-internals.h>
46 #include <mono/utils/mono-memory-model.h>
47 #include <mono/utils/checked-build.h>
48 #include <mono/utils/mono-threads.h>
49 #include <mono/utils/mono-threads-coop.h>
50 #include "cominterop.h"
51 #include <mono/utils/w32api.h>
54 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error);
57 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error);
60 free_main_args (void);
63 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error);
66 array_full_copy_unchecked_size (MonoArray *src, MonoArray *dest, MonoClass *klass, uintptr_t size);
69 class_get_virtual_method (MonoClass *klass, MonoMethod *method, gboolean is_proxy, MonoError *error);
71 /* Class lazy loading functions */
72 static GENERATE_GET_CLASS_WITH_CACHE (pointer, "System.Reflection", "Pointer")
73 static GENERATE_GET_CLASS_WITH_CACHE (remoting_services, "System.Runtime.Remoting", "RemotingServices")
74 static GENERATE_GET_CLASS_WITH_CACHE (unhandled_exception_event_args, "System", "UnhandledExceptionEventArgs")
75 static GENERATE_GET_CLASS_WITH_CACHE (sta_thread_attribute, "System", "STAThreadAttribute")
76 static GENERATE_GET_CLASS_WITH_CACHE (activation_services, "System.Runtime.Remoting.Activation", "ActivationServices")
79 #define ldstr_lock() mono_os_mutex_lock (&ldstr_section)
80 #define ldstr_unlock() mono_os_mutex_unlock (&ldstr_section)
81 static mono_mutex_t ldstr_section;
85 * mono_runtime_object_init:
86 * @this_obj: the object to initialize
88 * This function calls the zero-argument constructor (which must
89 * exist) for the given object.
92 mono_runtime_object_init (MonoObject *this_obj)
95 mono_runtime_object_init_checked (this_obj, &error);
96 mono_error_assert_ok (&error);
100 * mono_runtime_object_init_checked:
101 * @this_obj: the object to initialize
102 * @error: set on error.
104 * This function calls the zero-argument constructor (which must
105 * exist) for the given object and returns TRUE on success, or FALSE
106 * on error and sets @error.
109 mono_runtime_object_init_checked (MonoObject *this_obj, MonoError *error)
111 MONO_REQ_GC_UNSAFE_MODE;
113 MonoMethod *method = NULL;
114 MonoClass *klass = this_obj->vtable->klass;
116 mono_error_init (error);
117 method = mono_class_get_method_from_name (klass, ".ctor", 0);
119 g_error ("Could not lookup zero argument constructor for class %s", mono_type_get_full_name (klass));
121 if (method->klass->valuetype)
122 this_obj = (MonoObject *)mono_object_unbox (this_obj);
124 mono_runtime_invoke_checked (method, this_obj, NULL, error);
125 return is_ok (error);
128 /* The pseudo algorithm for type initialization from the spec
129 Note it doesn't say anything about domains - only threads.
131 2. If the type is initialized you are done.
132 2.1. If the type is not yet initialized, try to take an
134 2.2. If successful, record this thread as responsible for
135 initializing the type and proceed to step 2.3.
136 2.2.1. If not, see whether this thread or any thread
137 waiting for this thread to complete already holds the lock.
138 2.2.2. If so, return since blocking would create a deadlock. This thread
139 will now see an incompletely initialized state for the type,
140 but no deadlock will arise.
141 2.2.3 If not, block until the type is initialized then return.
142 2.3 Initialize the parent type and then all interfaces implemented
144 2.4 Execute the type initialization code for this type.
145 2.5 Mark the type as initialized, release the initialization lock,
146 awaken any threads waiting for this type to be initialized,
153 MonoNativeThreadId initializing_tid;
154 guint32 waiting_count;
157 /* condvar used to wait for 'done' becoming TRUE */
159 } TypeInitializationLock;
161 /* for locking access to type_initialization_hash and blocked_thread_hash */
162 static MonoCoopMutex type_initialization_section;
165 mono_type_initialization_lock (void)
167 /* The critical sections protected by this lock in mono_runtime_class_init_full () can block */
168 mono_coop_mutex_lock (&type_initialization_section);
172 mono_type_initialization_unlock (void)
174 mono_coop_mutex_unlock (&type_initialization_section);
178 mono_type_init_lock (TypeInitializationLock *lock)
180 MONO_REQ_GC_NEUTRAL_MODE;
182 mono_coop_mutex_lock (&lock->mutex);
186 mono_type_init_unlock (TypeInitializationLock *lock)
188 mono_coop_mutex_unlock (&lock->mutex);
191 /* from vtable to lock */
192 static GHashTable *type_initialization_hash;
194 /* from thread id to thread id being waited on */
195 static GHashTable *blocked_thread_hash;
198 static MonoThread *main_thread;
200 /* Functions supplied by the runtime */
201 static MonoRuntimeCallbacks callbacks;
204 * mono_thread_set_main:
205 * @thread: thread to set as the main thread
207 * This function can be used to instruct the runtime to treat @thread
208 * as the main thread, ie, the thread that would normally execute the Main()
209 * method. This basically means that at the end of @thread, the runtime will
210 * wait for the existing foreground threads to quit and other such details.
213 mono_thread_set_main (MonoThread *thread)
215 MONO_REQ_GC_UNSAFE_MODE;
217 static gboolean registered = FALSE;
220 MONO_GC_REGISTER_ROOT_SINGLE (main_thread, MONO_ROOT_SOURCE_THREADING, "main thread object");
224 main_thread = thread;
228 mono_thread_get_main (void)
230 MONO_REQ_GC_UNSAFE_MODE;
236 mono_type_initialization_init (void)
238 mono_coop_mutex_init_recursive (&type_initialization_section);
239 type_initialization_hash = g_hash_table_new (NULL, NULL);
240 blocked_thread_hash = g_hash_table_new (NULL, NULL);
241 mono_os_mutex_init_recursive (&ldstr_section);
245 mono_type_initialization_cleanup (void)
248 /* This is causing race conditions with
249 * mono_release_type_locks
251 mono_coop_mutex_destroy (&type_initialization_section);
252 g_hash_table_destroy (type_initialization_hash);
253 type_initialization_hash = NULL;
255 mono_os_mutex_destroy (&ldstr_section);
256 g_hash_table_destroy (blocked_thread_hash);
257 blocked_thread_hash = NULL;
263 * get_type_init_exception_for_vtable:
265 * Return the stored type initialization exception for VTABLE.
267 static MonoException*
268 get_type_init_exception_for_vtable (MonoVTable *vtable)
270 MONO_REQ_GC_UNSAFE_MODE;
273 MonoDomain *domain = vtable->domain;
274 MonoClass *klass = vtable->klass;
278 if (!vtable->init_failed)
279 g_error ("Trying to get the init exception for a non-failed vtable of class %s", mono_type_get_full_name (klass));
282 * If the initializing thread was rudely aborted, the exception is not stored
286 mono_domain_lock (domain);
287 if (domain->type_init_exception_hash)
288 ex = (MonoException *)mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
289 mono_domain_unlock (domain);
292 if (klass->name_space && *klass->name_space)
293 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
295 full_name = g_strdup (klass->name);
296 ex = mono_get_exception_type_initialization_checked (full_name, NULL, &error);
298 return_val_if_nok (&error, NULL);
305 * mono_runtime_class_init:
306 * @vtable: vtable that needs to be initialized
308 * This routine calls the class constructor for @vtable.
311 mono_runtime_class_init (MonoVTable *vtable)
313 MONO_REQ_GC_UNSAFE_MODE;
316 mono_runtime_class_init_full (vtable, &error);
317 mono_error_assert_ok (&error);
321 * Returns TRUE if the lock was freed.
322 * LOCKING: Caller should hold type_initialization_lock.
325 unref_type_lock (TypeInitializationLock *lock)
327 --lock->waiting_count;
328 if (lock->waiting_count == 0) {
329 mono_coop_mutex_destroy (&lock->mutex);
330 mono_coop_cond_destroy (&lock->cond);
339 * mono_runtime_class_init_full:
340 * @vtable that neeeds to be initialized
341 * @error set on error
343 * returns TRUE if class constructor .cctor has been initialized successfully, or FALSE otherwise and sets @error.
347 mono_runtime_class_init_full (MonoVTable *vtable, MonoError *error)
349 MONO_REQ_GC_UNSAFE_MODE;
351 MonoMethod *method = NULL;
354 MonoDomain *domain = vtable->domain;
355 TypeInitializationLock *lock;
356 MonoNativeThreadId tid;
357 int do_initialization = 0;
358 MonoDomain *last_domain = NULL;
359 MonoException * pending_tae = NULL;
361 mono_error_init (error);
363 if (vtable->initialized)
366 klass = vtable->klass;
368 if (!klass->image->checked_module_cctor) {
369 mono_image_check_for_module_cctor (klass->image);
370 if (klass->image->has_module_cctor) {
371 MonoClass *module_klass;
372 MonoVTable *module_vtable;
374 module_klass = mono_class_get_checked (klass->image, MONO_TOKEN_TYPE_DEF | 1, error);
379 module_vtable = mono_class_vtable_full (vtable->domain, module_klass, error);
382 if (!mono_runtime_class_init_full (module_vtable, error))
386 method = mono_class_get_cctor (klass);
388 vtable->initialized = 1;
392 tid = mono_native_thread_id_get ();
395 * Due some preprocessing inside a global lock. If we are the first thread
396 * trying to initialize this class, create a separate lock+cond var, and
397 * acquire it before leaving the global lock. The other threads will wait
401 mono_type_initialization_lock ();
402 /* double check... */
403 if (vtable->initialized) {
404 mono_type_initialization_unlock ();
407 if (vtable->init_failed) {
408 mono_type_initialization_unlock ();
410 /* The type initialization already failed once, rethrow the same exception */
411 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
414 lock = (TypeInitializationLock *)g_hash_table_lookup (type_initialization_hash, vtable);
416 /* This thread will get to do the initialization */
417 if (mono_domain_get () != domain) {
418 /* Transfer into the target domain */
419 last_domain = mono_domain_get ();
420 if (!mono_domain_set (domain, FALSE)) {
421 vtable->initialized = 1;
422 mono_type_initialization_unlock ();
423 mono_error_set_exception_instance (error, mono_get_exception_appdomain_unloaded ());
427 lock = (TypeInitializationLock *)g_malloc0 (sizeof (TypeInitializationLock));
428 mono_coop_mutex_init_recursive (&lock->mutex);
429 mono_coop_cond_init (&lock->cond);
430 lock->initializing_tid = tid;
431 lock->waiting_count = 1;
433 /* grab the vtable lock while this thread still owns type_initialization_section */
434 /* This is why type_initialization_lock needs to enter blocking mode */
435 mono_type_init_lock (lock);
436 g_hash_table_insert (type_initialization_hash, vtable, lock);
437 do_initialization = 1;
440 TypeInitializationLock *pending_lock;
442 if (mono_native_thread_id_equals (lock->initializing_tid, tid)) {
443 mono_type_initialization_unlock ();
446 /* see if the thread doing the initialization is already blocked on this thread */
447 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (lock->initializing_tid));
448 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
449 if (mono_native_thread_id_equals (pending_lock->initializing_tid, tid)) {
450 if (!pending_lock->done) {
451 mono_type_initialization_unlock ();
454 /* the thread doing the initialization is blocked on this thread,
455 but on a lock that has already been freed. It just hasn't got
460 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (pending_lock->initializing_tid));
462 ++lock->waiting_count;
463 /* record the fact that we are waiting on the initializing thread */
464 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
466 mono_type_initialization_unlock ();
468 if (do_initialization) {
469 MonoException *exc = NULL;
471 /* We are holding the per-vtable lock, do the actual initialization */
473 mono_threads_begin_abort_protected_block ();
474 mono_runtime_try_invoke (method, NULL, NULL, (MonoObject**) &exc, error);
475 gboolean got_pending_interrupt = mono_threads_end_abort_protected_block ();
477 //exception extracted, error will be set to the right value later
478 if (exc == NULL && !mono_error_ok (error))//invoking failed but exc was not set
479 exc = mono_error_convert_to_exception (error);
481 mono_error_cleanup (error);
483 mono_error_init (error);
485 /* If the initialization failed, mark the class as unusable. */
486 /* Avoid infinite loops */
488 (klass->image == mono_defaults.corlib &&
489 !strcmp (klass->name_space, "System") &&
490 !strcmp (klass->name, "TypeInitializationException")))) {
491 vtable->init_failed = 1;
493 if (klass->name_space && *klass->name_space)
494 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
496 full_name = g_strdup (klass->name);
498 MonoException *exc_to_throw = mono_get_exception_type_initialization_checked (full_name, exc, error);
501 mono_error_assert_ok (error); //We can't recover from this, no way to fail a type we can't alloc a failure.
504 * Store the exception object so it could be thrown on subsequent
507 mono_domain_lock (domain);
508 if (!domain->type_init_exception_hash)
509 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");
510 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
511 mono_domain_unlock (domain);
515 mono_domain_set (last_domain, TRUE);
516 /* Signal to the other threads that we are done */
518 mono_coop_cond_broadcast (&lock->cond);
520 mono_type_init_unlock (lock);
522 //This can happen if the cctor self-aborts
523 if (exc && mono_object_class (exc) == mono_defaults.threadabortexception_class)
526 //TAEs are blocked around .cctors, they must escape as soon as no cctor is left to run.
527 if (!pending_tae && got_pending_interrupt)
528 pending_tae = mono_thread_try_resume_interruption ();
530 /* this just blocks until the initializing thread is done */
531 mono_type_init_lock (lock);
533 mono_coop_cond_wait (&lock->cond, &lock->mutex);
534 mono_type_init_unlock (lock);
537 /* Do cleanup and setting vtable->initialized inside the global lock again */
538 mono_type_initialization_lock ();
539 if (!do_initialization)
540 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
541 gboolean deleted = unref_type_lock (lock);
543 g_hash_table_remove (type_initialization_hash, vtable);
544 /* Have to set this here since we check it inside the global lock */
545 if (do_initialization && !vtable->init_failed)
546 vtable->initialized = 1;
547 mono_type_initialization_unlock ();
551 mono_error_set_exception_instance (error, pending_tae);
552 else if (vtable->init_failed) {
553 /* Either we were the initializing thread or we waited for the initialization */
554 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
561 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
563 MONO_REQ_GC_NEUTRAL_MODE;
565 MonoVTable *vtable = (MonoVTable*)key;
567 TypeInitializationLock *lock = (TypeInitializationLock*) value;
568 if (mono_native_thread_id_equals (lock->initializing_tid, MONO_UINT_TO_NATIVE_THREAD_ID (GPOINTER_TO_UINT (user))) && !lock->done) {
571 * Have to set this since it cannot be set by the normal code in
572 * mono_runtime_class_init (). In this case, the exception object is not stored,
573 * and get_type_init_exception_for_class () needs to be aware of this.
575 vtable->init_failed = 1;
576 mono_coop_cond_broadcast (&lock->cond);
577 mono_type_init_unlock (lock);
578 gboolean deleted = unref_type_lock (lock);
586 mono_release_type_locks (MonoInternalThread *thread)
588 MONO_REQ_GC_UNSAFE_MODE;
590 mono_type_initialization_lock ();
591 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, GUINT_TO_POINTER (thread->tid));
592 mono_type_initialization_unlock ();
595 #ifndef DISABLE_REMOTING
598 create_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error)
600 if (!callbacks.create_remoting_trampoline)
601 g_error ("remoting not installed");
602 return callbacks.create_remoting_trampoline (domain, method, target, error);
607 static MonoImtTrampolineBuilder imt_trampoline_builder;
608 static gboolean always_build_imt_trampolines;
610 #if (MONO_IMT_SIZE > 32)
611 #error "MONO_IMT_SIZE cannot be larger than 32"
615 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
617 memcpy (&callbacks, cbs, sizeof (*cbs));
620 MonoRuntimeCallbacks*
621 mono_get_runtime_callbacks (void)
627 mono_install_imt_trampoline_builder (MonoImtTrampolineBuilder func)
629 imt_trampoline_builder = func;
633 mono_set_always_build_imt_trampolines (gboolean value)
635 always_build_imt_trampolines = value;
639 * mono_compile_method:
640 * @method: The method to compile.
642 * This JIT-compiles the method, and returns the pointer to the native code
646 mono_compile_method (MonoMethod *method)
649 gpointer result = mono_compile_method_checked (method, &error);
650 mono_error_cleanup (&error);
655 * mono_compile_method:
656 * @method: The method to compile.
657 * @error: set on error.
659 * This JIT-compiles the method, and returns the pointer to the native code
660 * produced. On failure returns NULL and sets @error.
663 mono_compile_method_checked (MonoMethod *method, MonoError *error)
667 MONO_REQ_GC_NEUTRAL_MODE
669 mono_error_init (error);
671 g_assert (callbacks.compile_method);
672 res = callbacks.compile_method (method, error);
677 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper, MonoError *error)
681 MONO_REQ_GC_NEUTRAL_MODE;
683 mono_error_init (error);
684 res = callbacks.create_jump_trampoline (domain, method, add_sync_wrapper, error);
689 mono_runtime_create_delegate_trampoline (MonoClass *klass)
691 MONO_REQ_GC_NEUTRAL_MODE
693 g_assert (callbacks.create_delegate_trampoline);
694 return callbacks.create_delegate_trampoline (mono_domain_get (), klass);
698 * mono_runtime_free_method:
699 * @domain; domain where the method is hosted
700 * @method: method to release
702 * This routine is invoked to free the resources associated with
703 * a method that has been JIT compiled. This is used to discard
704 * methods that were used only temporarily (for example, used in marshalling)
708 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
710 MONO_REQ_GC_NEUTRAL_MODE
712 if (callbacks.free_method)
713 callbacks.free_method (domain, method);
715 mono_method_clear_object (domain, method);
717 mono_free_method (method);
721 * The vtables in the root appdomain are assumed to be reachable by other
722 * roots, and we don't use typed allocation in the other domains.
725 /* The sync block is no longer a GC pointer */
726 #define GC_HEADER_BITMAP (0)
728 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
731 compute_class_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
733 MONO_REQ_GC_NEUTRAL_MODE;
735 MonoClassField *field;
741 max_size = mono_class_data_size (klass) / sizeof (gpointer);
743 max_size = klass->instance_size / sizeof (gpointer);
744 if (max_size > size) {
745 g_assert (offset <= 0);
746 bitmap = (gsize *)g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
751 /*An Ephemeron cannot be marked by sgen*/
752 if (!static_fields && klass->image == mono_defaults.corlib && !strcmp ("Ephemeron", klass->name)) {
754 memset (bitmap, 0, size / 8);
759 for (p = klass; p != NULL; p = p->parent) {
760 gpointer iter = NULL;
761 while ((field = mono_class_get_fields (p, &iter))) {
765 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
767 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
770 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
773 /* FIXME: should not happen, flag as type load error */
774 if (field->type->byref)
777 if (static_fields && field->offset == -1)
781 pos = field->offset / sizeof (gpointer);
784 type = mono_type_get_underlying_type (field->type);
785 switch (type->type) {
789 case MONO_TYPE_FNPTR:
791 case MONO_TYPE_STRING:
792 case MONO_TYPE_SZARRAY:
793 case MONO_TYPE_CLASS:
794 case MONO_TYPE_OBJECT:
795 case MONO_TYPE_ARRAY:
796 g_assert ((field->offset % sizeof(gpointer)) == 0);
798 g_assert (pos < size || pos <= max_size);
799 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
800 *max_set = MAX (*max_set, pos);
802 case MONO_TYPE_GENERICINST:
803 if (!mono_type_generic_inst_is_valuetype (type)) {
804 g_assert ((field->offset % sizeof(gpointer)) == 0);
806 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
807 *max_set = MAX (*max_set, pos);
812 case MONO_TYPE_VALUETYPE: {
813 MonoClass *fclass = mono_class_from_mono_type (field->type);
814 if (fclass->has_references) {
815 /* remove the object header */
816 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
830 case MONO_TYPE_BOOLEAN:
834 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
845 * mono_class_compute_bitmap:
847 * Mono internal function to compute a bitmap of reference fields in a class.
850 mono_class_compute_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
852 MONO_REQ_GC_NEUTRAL_MODE;
854 return compute_class_bitmap (klass, bitmap, size, offset, max_set, static_fields);
859 * similar to the above, but sets the bits in the bitmap for any non-ref field
860 * and ignores static fields
863 compute_class_non_ref_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset)
865 MonoClassField *field;
870 max_size = class->instance_size / sizeof (gpointer);
871 if (max_size >= size) {
872 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
875 for (p = class; p != NULL; p = p->parent) {
876 gpointer iter = NULL;
877 while ((field = mono_class_get_fields (p, &iter))) {
880 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
882 /* FIXME: should not happen, flag as type load error */
883 if (field->type->byref)
886 pos = field->offset / sizeof (gpointer);
889 type = mono_type_get_underlying_type (field->type);
890 switch (type->type) {
891 #if SIZEOF_VOID_P == 8
895 case MONO_TYPE_FNPTR:
900 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
901 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
902 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
905 #if SIZEOF_VOID_P == 4
909 case MONO_TYPE_FNPTR:
914 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
915 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
916 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
922 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
923 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
924 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
927 case MONO_TYPE_BOOLEAN:
930 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
932 case MONO_TYPE_STRING:
933 case MONO_TYPE_SZARRAY:
934 case MONO_TYPE_CLASS:
935 case MONO_TYPE_OBJECT:
936 case MONO_TYPE_ARRAY:
938 case MONO_TYPE_GENERICINST:
939 if (!mono_type_generic_inst_is_valuetype (type)) {
944 case MONO_TYPE_VALUETYPE: {
945 MonoClass *fclass = mono_class_from_mono_type (field->type);
946 /* remove the object header */
947 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
951 g_assert_not_reached ();
960 * mono_class_insecure_overlapping:
961 * check if a class with explicit layout has references and non-references
962 * fields overlapping.
964 * Returns: TRUE if it is insecure to load the type.
967 mono_class_insecure_overlapping (MonoClass *klass)
971 gsize default_bitmap [4] = {0};
973 gsize default_nrbitmap [4] = {0};
974 int i, insecure = FALSE;
977 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
978 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
980 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
981 int idx = i % (sizeof (bitmap [0]) * 8);
982 if (bitmap [idx] & nrbitmap [idx]) {
987 if (bitmap != default_bitmap)
989 if (nrbitmap != default_nrbitmap)
992 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
1000 ves_icall_string_alloc (int length)
1003 MonoString *str = mono_string_new_size_checked (mono_domain_get (), length, &error);
1004 mono_error_set_pending_exception (&error);
1009 /* LOCKING: Acquires the loader lock */
1011 mono_class_compute_gc_descriptor (MonoClass *klass)
1013 MONO_REQ_GC_NEUTRAL_MODE;
1017 gsize default_bitmap [4] = {0};
1018 static gboolean gcj_inited = FALSE;
1019 MonoGCDescriptor gc_descr;
1022 mono_loader_lock ();
1024 mono_register_jit_icall (ves_icall_object_new_fast, "ves_icall_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
1025 mono_register_jit_icall (ves_icall_string_alloc, "ves_icall_string_alloc", mono_create_icall_signature ("object int"), FALSE);
1028 mono_loader_unlock ();
1032 mono_class_init (klass);
1034 if (klass->gc_descr_inited)
1037 bitmap = default_bitmap;
1038 if (klass == mono_defaults.string_class) {
1039 gc_descr = mono_gc_make_descr_for_string (bitmap, 2);
1040 } else if (klass->rank) {
1041 mono_class_compute_gc_descriptor (klass->element_class);
1042 if (MONO_TYPE_IS_REFERENCE (&klass->element_class->byval_arg)) {
1044 gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
1045 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1046 class->name_space, class->name);*/
1048 /* remove the object header */
1049 bitmap = compute_class_bitmap (klass->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
1050 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));
1051 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1052 class->name_space, class->name);*/
1053 if (bitmap != default_bitmap)
1057 /*static int count = 0;
1060 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1061 gc_descr = mono_gc_make_descr_for_object (bitmap, max_set + 1, klass->instance_size);
1063 if (class->gc_descr == MONO_GC_DESCRIPTOR_NULL)
1064 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
1066 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
1067 if (bitmap != default_bitmap)
1071 /* Publish the data */
1072 mono_loader_lock ();
1073 klass->gc_descr = gc_descr;
1074 mono_memory_barrier ();
1075 klass->gc_descr_inited = TRUE;
1076 mono_loader_unlock ();
1080 * field_is_special_static:
1081 * @fklass: The MonoClass to look up.
1082 * @field: The MonoClassField describing the field.
1084 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1085 * SPECIAL_STATIC_NONE otherwise.
1088 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1090 MONO_REQ_GC_NEUTRAL_MODE;
1093 MonoCustomAttrInfo *ainfo;
1095 ainfo = mono_custom_attrs_from_field_checked (fklass, field, &error);
1096 mono_error_cleanup (&error); /* FIXME don't swallow the error? */
1099 for (i = 0; i < ainfo->num_attrs; ++i) {
1100 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1101 if (klass->image == mono_defaults.corlib) {
1102 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1103 mono_custom_attrs_free (ainfo);
1104 return SPECIAL_STATIC_THREAD;
1106 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1107 mono_custom_attrs_free (ainfo);
1108 return SPECIAL_STATIC_CONTEXT;
1112 mono_custom_attrs_free (ainfo);
1113 return SPECIAL_STATIC_NONE;
1116 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1117 #define mix(a,b,c) { \
1118 a -= c; a ^= rot(c, 4); c += b; \
1119 b -= a; b ^= rot(a, 6); a += c; \
1120 c -= b; c ^= rot(b, 8); b += a; \
1121 a -= c; a ^= rot(c,16); c += b; \
1122 b -= a; b ^= rot(a,19); a += c; \
1123 c -= b; c ^= rot(b, 4); b += a; \
1125 #define final(a,b,c) { \
1126 c ^= b; c -= rot(b,14); \
1127 a ^= c; a -= rot(c,11); \
1128 b ^= a; b -= rot(a,25); \
1129 c ^= b; c -= rot(b,16); \
1130 a ^= c; a -= rot(c,4); \
1131 b ^= a; b -= rot(a,14); \
1132 c ^= b; c -= rot(b,24); \
1136 * mono_method_get_imt_slot:
1138 * The IMT slot is embedded into AOTed code, so this must return the same value
1139 * for the same method across all executions. This means:
1140 * - pointers shouldn't be used as hash values.
1141 * - mono_metadata_str_hash () should be used for hashing strings.
1144 mono_method_get_imt_slot (MonoMethod *method)
1146 MONO_REQ_GC_NEUTRAL_MODE;
1148 MonoMethodSignature *sig;
1150 guint32 *hashes_start, *hashes;
1154 /* This can be used to stress tests the collision code */
1158 * We do this to simplify generic sharing. It will hurt
1159 * performance in cases where a class implements two different
1160 * instantiations of the same generic interface.
1161 * The code in build_imt_slots () depends on this.
1163 if (method->is_inflated)
1164 method = ((MonoMethodInflated*)method)->declaring;
1166 sig = mono_method_signature (method);
1167 hashes_count = sig->param_count + 4;
1168 hashes_start = (guint32 *)malloc (hashes_count * sizeof (guint32));
1169 hashes = hashes_start;
1171 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1172 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1173 method->klass->name_space, method->klass->name, method->name);
1176 /* Initialize hashes */
1177 hashes [0] = mono_metadata_str_hash (method->klass->name);
1178 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1179 hashes [2] = mono_metadata_str_hash (method->name);
1180 hashes [3] = mono_metadata_type_hash (sig->ret);
1181 for (i = 0; i < sig->param_count; i++) {
1182 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1185 /* Setup internal state */
1186 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1188 /* Handle most of the hashes */
1189 while (hashes_count > 3) {
1198 /* Handle the last 3 hashes (all the case statements fall through) */
1199 switch (hashes_count) {
1200 case 3 : c += hashes [2];
1201 case 2 : b += hashes [1];
1202 case 1 : a += hashes [0];
1204 case 0: /* nothing left to add */
1208 g_free (hashes_start);
1209 /* Report the result */
1210 return c % MONO_IMT_SIZE;
1219 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1220 MONO_REQ_GC_NEUTRAL_MODE;
1222 guint32 imt_slot = mono_method_get_imt_slot (method);
1223 MonoImtBuilderEntry *entry;
1225 if (slot_num >= 0 && imt_slot != slot_num) {
1226 /* we build just a single imt slot and this is not it */
1230 entry = (MonoImtBuilderEntry *)g_malloc0 (sizeof (MonoImtBuilderEntry));
1231 entry->key = method;
1232 entry->value.vtable_slot = vtable_slot;
1233 entry->next = imt_builder [imt_slot];
1234 if (imt_builder [imt_slot] != NULL) {
1235 entry->children = imt_builder [imt_slot]->children + 1;
1236 if (entry->children == 1) {
1237 mono_stats.imt_slots_with_collisions++;
1238 *imt_collisions_bitmap |= (1 << imt_slot);
1241 entry->children = 0;
1242 mono_stats.imt_used_slots++;
1244 imt_builder [imt_slot] = entry;
1247 char *method_name = mono_method_full_name (method, TRUE);
1248 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1249 method, method_name, imt_slot, vtable_slot, entry->children);
1250 g_free (method_name);
1257 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1259 MonoMethod *method = e->key;
1260 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1264 method->klass->name_space,
1265 method->klass->name,
1268 printf (" * %s: NULL\n", message);
1274 compare_imt_builder_entries (const void *p1, const void *p2) {
1275 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1276 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1278 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1282 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1284 MONO_REQ_GC_NEUTRAL_MODE;
1286 int count = end - start;
1287 int chunk_start = out_array->len;
1290 for (i = start; i < end; ++i) {
1291 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1292 item->key = sorted_array [i]->key;
1293 item->value = sorted_array [i]->value;
1294 item->has_target_code = sorted_array [i]->has_target_code;
1295 item->is_equals = TRUE;
1297 item->check_target_idx = out_array->len + 1;
1299 item->check_target_idx = 0;
1300 g_ptr_array_add (out_array, item);
1303 int middle = start + count / 2;
1304 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1306 item->key = sorted_array [middle]->key;
1307 item->is_equals = FALSE;
1308 g_ptr_array_add (out_array, item);
1309 imt_emit_ir (sorted_array, start, middle, out_array);
1310 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1316 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1317 MONO_REQ_GC_NEUTRAL_MODE;
1319 int number_of_entries = entries->children + 1;
1320 MonoImtBuilderEntry **sorted_array = (MonoImtBuilderEntry **)malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1321 GPtrArray *result = g_ptr_array_new ();
1322 MonoImtBuilderEntry *current_entry;
1325 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1326 sorted_array [i] = current_entry;
1328 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1330 /*for (i = 0; i < number_of_entries; i++) {
1331 print_imt_entry (" sorted array:", sorted_array [i], i);
1334 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1336 g_free (sorted_array);
1341 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1343 MONO_REQ_GC_NEUTRAL_MODE;
1345 if (imt_builder_entry != NULL) {
1346 if (imt_builder_entry->children == 0 && !fail_tramp && !always_build_imt_trampolines) {
1347 /* No collision, return the vtable slot contents */
1348 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1350 /* Collision, build the trampoline */
1351 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1354 result = imt_trampoline_builder (vtable, domain,
1355 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1356 for (i = 0; i < imt_ir->len; ++i)
1357 g_free (g_ptr_array_index (imt_ir, i));
1358 g_ptr_array_free (imt_ir, TRUE);
1370 static MonoImtBuilderEntry*
1371 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1374 * LOCKING: requires the loader and domain locks.
1378 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1380 MONO_REQ_GC_NEUTRAL_MODE;
1384 guint32 imt_collisions_bitmap = 0;
1385 MonoImtBuilderEntry **imt_builder = (MonoImtBuilderEntry **)calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1386 int method_count = 0;
1387 gboolean record_method_count_for_max_collisions = FALSE;
1388 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1391 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1393 for (i = 0; i < klass->interface_offsets_count; ++i) {
1394 MonoClass *iface = klass->interfaces_packed [i];
1395 int interface_offset = klass->interface_offsets_packed [i];
1396 int method_slot_in_interface, vt_slot;
1398 if (mono_class_has_variant_generic_params (iface))
1399 has_variant_iface = TRUE;
1401 mono_class_setup_methods (iface);
1402 vt_slot = interface_offset;
1403 int mcount = mono_class_get_method_count (iface);
1404 for (method_slot_in_interface = 0; method_slot_in_interface < mcount; method_slot_in_interface++) {
1407 if (slot_num >= 0 && mono_class_is_ginst (iface)) {
1409 * The imt slot of the method is the same as for its declaring method,
1410 * see the comment in mono_method_get_imt_slot (), so we can
1411 * avoid inflating methods which will be discarded by
1412 * add_imt_builder_entry anyway.
1414 method = mono_class_get_method_by_index (mono_class_get_generic_class (iface)->container_class, method_slot_in_interface);
1415 if (mono_method_get_imt_slot (method) != slot_num) {
1420 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1421 if (method->is_generic) {
1422 has_generic_virtual = TRUE;
1427 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1428 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1433 if (extra_interfaces) {
1434 int interface_offset = klass->vtable_size;
1436 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1437 MonoClass* iface = (MonoClass *)list_item->data;
1438 int method_slot_in_interface;
1439 int mcount = mono_class_get_method_count (iface);
1440 for (method_slot_in_interface = 0; method_slot_in_interface < mcount; method_slot_in_interface++) {
1441 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1443 if (method->is_generic)
1444 has_generic_virtual = TRUE;
1445 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1447 interface_offset += mcount;
1450 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1451 /* overwrite the imt slot only if we're building all the entries or if
1452 * we're building this specific one
1454 if (slot_num < 0 || i == slot_num) {
1455 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1458 if (imt_builder [i]) {
1459 MonoImtBuilderEntry *entry;
1461 /* Link entries with imt_builder [i] */
1462 for (entry = entries; entry->next; entry = entry->next) {
1464 MonoMethod *method = (MonoMethod*)entry->key;
1465 char *method_name = mono_method_full_name (method, TRUE);
1466 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1467 g_free (method_name);
1470 entry->next = imt_builder [i];
1471 entries->children += imt_builder [i]->children + 1;
1473 imt_builder [i] = entries;
1476 if (has_generic_virtual || has_variant_iface) {
1478 * There might be collisions later when the the trampoline is expanded.
1480 imt_collisions_bitmap |= (1 << i);
1483 * The IMT trampoline might be called with an instance of one of the
1484 * generic virtual methods, so has to fallback to the IMT trampoline.
1486 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline (vt, i));
1488 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1491 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1495 if (imt_builder [i] != NULL) {
1496 int methods_in_slot = imt_builder [i]->children + 1;
1497 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1498 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1499 record_method_count_for_max_collisions = TRUE;
1501 method_count += methods_in_slot;
1505 mono_stats.imt_number_of_methods += method_count;
1506 if (record_method_count_for_max_collisions) {
1507 mono_stats.imt_method_count_when_max_collisions = method_count;
1510 for (i = 0; i < MONO_IMT_SIZE; i++) {
1511 MonoImtBuilderEntry* entry = imt_builder [i];
1512 while (entry != NULL) {
1513 MonoImtBuilderEntry* next = entry->next;
1518 g_free (imt_builder);
1519 /* we OR the bitmap since we may build just a single imt slot at a time */
1520 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1524 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1525 MONO_REQ_GC_NEUTRAL_MODE;
1527 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1531 * mono_vtable_build_imt_slot:
1532 * @vtable: virtual object table struct
1533 * @imt_slot: slot in the IMT table
1535 * Fill the given @imt_slot in the IMT table of @vtable with
1536 * a trampoline or a trampoline for the case of collisions.
1537 * This is part of the internal mono API.
1539 * LOCKING: Take the domain lock.
1542 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1544 MONO_REQ_GC_NEUTRAL_MODE;
1546 gpointer *imt = (gpointer*)vtable;
1547 imt -= MONO_IMT_SIZE;
1548 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1550 /* no support for extra interfaces: the proxy objects will need
1551 * to build the complete IMT
1552 * Update and heck needs to ahppen inside the proper domain lock, as all
1553 * the changes made to a MonoVTable.
1555 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1556 mono_domain_lock (vtable->domain);
1557 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1558 if (!callbacks.imt_entry_inited (vtable, imt_slot))
1559 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1560 mono_domain_unlock (vtable->domain);
1561 mono_loader_unlock ();
1564 #define THUNK_THRESHOLD 10
1567 * mono_method_alloc_generic_virtual_trampoline:
1569 * @size: size in bytes
1571 * Allocs size bytes to be used for the code of a generic virtual
1572 * trampoline. It's either allocated from the domain's code manager or
1573 * reused from a previously invalidated piece.
1575 * LOCKING: The domain lock must be held.
1578 mono_method_alloc_generic_virtual_trampoline (MonoDomain *domain, int size)
1580 MONO_REQ_GC_NEUTRAL_MODE;
1582 static gboolean inited = FALSE;
1583 static int generic_virtual_trampolines_size = 0;
1586 mono_counters_register ("Generic virtual trampoline bytes",
1587 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_trampolines_size);
1590 generic_virtual_trampolines_size += size;
1592 return mono_domain_code_reserve (domain, size);
1595 typedef struct _GenericVirtualCase {
1599 struct _GenericVirtualCase *next;
1600 } GenericVirtualCase;
1603 * get_generic_virtual_entries:
1605 * Return IMT entries for the generic virtual method instances and
1606 * variant interface methods for vtable slot
1609 static MonoImtBuilderEntry*
1610 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1612 MONO_REQ_GC_NEUTRAL_MODE;
1614 GenericVirtualCase *list;
1615 MonoImtBuilderEntry *entries;
1617 mono_domain_lock (domain);
1618 if (!domain->generic_virtual_cases)
1619 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1621 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1624 for (; list; list = list->next) {
1625 MonoImtBuilderEntry *entry;
1627 if (list->count < THUNK_THRESHOLD)
1630 entry = g_new0 (MonoImtBuilderEntry, 1);
1631 entry->key = list->method;
1632 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1633 entry->has_target_code = 1;
1635 entry->children = entries->children + 1;
1636 entry->next = entries;
1640 mono_domain_unlock (domain);
1642 /* FIXME: Leaking memory ? */
1647 * mono_method_add_generic_virtual_invocation:
1649 * @vtable_slot: pointer to the vtable slot
1650 * @method: the inflated generic virtual method
1651 * @code: the method's code
1653 * Registers a call via unmanaged code to a generic virtual method
1654 * instantiation or variant interface method. If the number of calls reaches a threshold
1655 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1656 * virtual method trampoline.
1659 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1660 gpointer *vtable_slot,
1661 MonoMethod *method, gpointer code)
1663 MONO_REQ_GC_NEUTRAL_MODE;
1665 static gboolean inited = FALSE;
1666 static int num_added = 0;
1667 static int num_freed = 0;
1669 GenericVirtualCase *gvc, *list;
1670 MonoImtBuilderEntry *entries;
1674 mono_domain_lock (domain);
1675 if (!domain->generic_virtual_cases)
1676 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1679 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1680 mono_counters_register ("Freed IMT trampolines", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_freed);
1684 /* Check whether the case was already added */
1685 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1688 if (gvc->method == method)
1693 /* If not found, make a new one */
1695 gvc = (GenericVirtualCase *)mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1696 gvc->method = method;
1699 gvc->next = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1701 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1706 if (++gvc->count == THUNK_THRESHOLD) {
1707 gpointer *old_thunk = (void **)*vtable_slot;
1708 gpointer vtable_trampoline = NULL;
1709 gpointer imt_trampoline = NULL;
1711 if ((gpointer)vtable_slot < (gpointer)vtable) {
1712 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1713 int imt_slot = MONO_IMT_SIZE + displacement;
1715 /* Force the rebuild of the trampoline at the next call */
1716 imt_trampoline = callbacks.get_imt_trampoline (vtable, imt_slot);
1717 *vtable_slot = imt_trampoline;
1719 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline (vtable, (gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1721 entries = get_generic_virtual_entries (domain, vtable_slot);
1723 sorted = imt_sort_slot_entries (entries);
1725 *vtable_slot = imt_trampoline_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1729 MonoImtBuilderEntry *next = entries->next;
1734 for (i = 0; i < sorted->len; ++i)
1735 g_free (g_ptr_array_index (sorted, i));
1736 g_ptr_array_free (sorted, TRUE);
1738 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1743 mono_domain_unlock (domain);
1746 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error);
1749 * mono_class_vtable:
1750 * @domain: the application domain
1751 * @class: the class to initialize
1753 * VTables are domain specific because we create domain specific code, and
1754 * they contain the domain specific static class data.
1755 * On failure, NULL is returned, and class->exception_type is set.
1758 mono_class_vtable (MonoDomain *domain, MonoClass *klass)
1761 MonoVTable* vtable = mono_class_vtable_full (domain, klass, &error);
1762 mono_error_cleanup (&error);
1767 * mono_class_vtable_full:
1768 * @domain: the application domain
1769 * @class: the class to initialize
1770 * @error set on failure.
1772 * VTables are domain specific because we create domain specific code, and
1773 * they contain the domain specific static class data.
1776 mono_class_vtable_full (MonoDomain *domain, MonoClass *klass, MonoError *error)
1778 MONO_REQ_GC_UNSAFE_MODE;
1780 MonoClassRuntimeInfo *runtime_info;
1782 mono_error_init (error);
1786 if (mono_class_has_failure (klass)) {
1787 mono_error_set_for_class_failure (error, klass);
1791 /* this check can be inlined in jitted code, too */
1792 runtime_info = klass->runtime_info;
1793 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1794 return runtime_info->domain_vtables [domain->domain_id];
1795 return mono_class_create_runtime_vtable (domain, klass, error);
1799 * mono_class_try_get_vtable:
1800 * @domain: the application domain
1801 * @class: the class to initialize
1803 * This function tries to get the associated vtable from @class if
1804 * it was already created.
1807 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *klass)
1809 MONO_REQ_GC_NEUTRAL_MODE;
1811 MonoClassRuntimeInfo *runtime_info;
1815 runtime_info = klass->runtime_info;
1816 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1817 return runtime_info->domain_vtables [domain->domain_id];
1822 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1824 MONO_REQ_GC_NEUTRAL_MODE;
1826 size_t alloc_offset;
1829 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1830 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1831 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1833 if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1834 g_assert ((imt_table_bytes & 7) == 4);
1841 return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1845 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error)
1847 MONO_REQ_GC_UNSAFE_MODE;
1850 MonoClassRuntimeInfo *runtime_info, *old_info;
1851 MonoClassField *field;
1853 int i, vtable_slots;
1854 size_t imt_table_bytes;
1856 guint32 vtable_size, class_size;
1858 gpointer *interface_offsets;
1860 mono_error_init (error);
1862 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1863 mono_domain_lock (domain);
1864 runtime_info = klass->runtime_info;
1865 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1866 mono_domain_unlock (domain);
1867 mono_loader_unlock ();
1868 return runtime_info->domain_vtables [domain->domain_id];
1870 if (!klass->inited || mono_class_has_failure (klass)) {
1871 if (!mono_class_init (klass) || mono_class_has_failure (klass)) {
1872 mono_domain_unlock (domain);
1873 mono_loader_unlock ();
1874 mono_error_set_for_class_failure (error, klass);
1879 /* Array types require that their element type be valid*/
1880 if (klass->byval_arg.type == MONO_TYPE_ARRAY || klass->byval_arg.type == MONO_TYPE_SZARRAY) {
1881 MonoClass *element_class = klass->element_class;
1882 if (!element_class->inited)
1883 mono_class_init (element_class);
1885 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1886 if (!mono_class_has_failure (element_class) && !element_class->vtable_size)
1887 mono_class_setup_vtable (element_class);
1889 if (mono_class_has_failure (element_class)) {
1890 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1891 if (!mono_class_has_failure (klass))
1892 mono_class_set_type_load_failure (klass, "");
1893 mono_domain_unlock (domain);
1894 mono_loader_unlock ();
1895 mono_error_set_for_class_failure (error, klass);
1901 * For some classes, mono_class_init () already computed klass->vtable_size, and
1902 * that is all that is needed because of the vtable trampolines.
1904 if (!klass->vtable_size)
1905 mono_class_setup_vtable (klass);
1907 if (mono_class_is_ginst (klass) && !klass->vtable)
1908 mono_class_check_vtable_constraints (klass, NULL);
1910 /* Initialize klass->has_finalize */
1911 mono_class_has_finalizer (klass);
1913 if (mono_class_has_failure (klass)) {
1914 mono_domain_unlock (domain);
1915 mono_loader_unlock ();
1916 mono_error_set_for_class_failure (error, klass);
1920 vtable_slots = klass->vtable_size;
1921 /* we add an additional vtable slot to store the pointer to static field data only when needed */
1922 class_size = mono_class_data_size (klass);
1926 if (klass->interface_offsets_count) {
1927 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1928 mono_stats.imt_number_of_tables++;
1929 mono_stats.imt_tables_size += imt_table_bytes;
1931 imt_table_bytes = 0;
1934 vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
1936 mono_stats.used_class_count++;
1937 mono_stats.class_vtable_size += vtable_size;
1939 interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
1940 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1941 g_assert (!((gsize)vt & 7));
1944 vt->rank = klass->rank;
1945 vt->domain = domain;
1947 mono_class_compute_gc_descriptor (klass);
1949 * We can't use typed allocation in the non-root domains, since the
1950 * collector needs the GC descriptor stored in the vtable even after
1951 * the mempool containing the vtable is destroyed when the domain is
1952 * unloaded. An alternative might be to allocate vtables in the GC
1953 * heap, but this does not seem to work (it leads to crashes inside
1954 * libgc). If that approach is tried, two gc descriptors need to be
1955 * allocated for each class: one for the root domain, and one for all
1956 * other domains. The second descriptor should contain a bit for the
1957 * vtable field in MonoObject, since we can no longer assume the
1958 * vtable is reachable by other roots after the appdomain is unloaded.
1960 #ifdef HAVE_BOEHM_GC
1961 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1962 vt->gc_descr = MONO_GC_DESCRIPTOR_NULL;
1965 vt->gc_descr = klass->gc_descr;
1967 gc_bits = mono_gc_get_vtable_bits (klass);
1968 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
1970 vt->gc_bits = gc_bits;
1973 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
1974 if (klass->has_static_refs) {
1975 MonoGCDescriptor statics_gc_descr;
1977 gsize default_bitmap [4] = {0};
1980 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1981 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], klass->name_space, klass->name, class_size);*/
1982 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1983 vt->vtable [klass->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr, MONO_ROOT_SOURCE_STATIC, "managed static variables");
1984 mono_domain_add_class_static_data (domain, klass, vt->vtable [klass->vtable_size], NULL);
1985 if (bitmap != default_bitmap)
1988 vt->vtable [klass->vtable_size] = mono_domain_alloc0 (domain, class_size);
1990 vt->has_static_fields = TRUE;
1991 mono_stats.class_static_data_size += class_size;
1995 while ((field = mono_class_get_fields (klass, &iter))) {
1996 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1998 if (mono_field_is_deleted (field))
2000 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2001 gint32 special_static = klass->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (klass, field);
2002 if (special_static != SPECIAL_STATIC_NONE) {
2003 guint32 size, offset;
2005 gsize default_bitmap [4] = {0};
2010 if (mono_type_is_reference (field->type)) {
2011 default_bitmap [0] = 1;
2013 bitmap = default_bitmap;
2014 } else if (mono_type_is_struct (field->type)) {
2015 fclass = mono_class_from_mono_type (field->type);
2016 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
2017 numbits = max_set + 1;
2019 default_bitmap [0] = 0;
2021 bitmap = default_bitmap;
2023 size = mono_type_size (field->type, &align);
2024 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
2025 if (!domain->special_static_fields)
2026 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2027 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2028 if (bitmap != default_bitmap)
2031 * This marks the field as special static to speed up the
2032 * checks in mono_field_static_get/set_value ().
2038 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2039 MonoClass *fklass = mono_class_from_mono_type (field->type);
2040 const char *data = mono_field_get_data (field);
2042 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2043 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2044 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2047 if (fklass->valuetype) {
2048 memcpy (t, data, mono_class_value_size (fklass, NULL));
2050 /* it's a pointer type: add check */
2051 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2058 vt->max_interface_id = klass->max_interface_id;
2059 vt->interface_bitmap = klass->interface_bitmap;
2061 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2062 // class->name, klass->interface_offsets_count);
2064 /* Initialize vtable */
2065 if (callbacks.get_vtable_trampoline) {
2066 // This also covers the AOT case
2067 for (i = 0; i < klass->vtable_size; ++i) {
2068 vt->vtable [i] = callbacks.get_vtable_trampoline (vt, i);
2071 mono_class_setup_vtable (klass);
2073 for (i = 0; i < klass->vtable_size; ++i) {
2076 cm = klass->vtable [i];
2078 vt->vtable [i] = callbacks.create_jit_trampoline (domain, cm, error);
2079 if (!is_ok (error)) {
2080 mono_domain_unlock (domain);
2081 mono_loader_unlock ();
2088 if (imt_table_bytes) {
2089 /* Now that the vtable is full, we can actually fill up the IMT */
2090 for (i = 0; i < MONO_IMT_SIZE; ++i)
2091 interface_offsets [i] = callbacks.get_imt_trampoline (vt, i);
2095 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2096 * re-acquire them and check if another thread has created the vtable in the meantime.
2098 /* Special case System.MonoType to avoid infinite recursion */
2099 if (klass != mono_defaults.runtimetype_class) {
2100 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2101 if (!is_ok (error)) {
2102 mono_domain_unlock (domain);
2103 mono_loader_unlock ();
2107 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2108 /* This is unregistered in
2109 unregister_vtable_reflection_type() in
2111 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2114 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (klass));
2116 /* class_vtable_array keeps an array of created vtables
2118 g_ptr_array_add (domain->class_vtable_array, vt);
2119 /* klass->runtime_info is protected by the loader lock, both when
2120 * it it enlarged and when it is stored info.
2124 * Store the vtable in klass->runtime_info.
2125 * klass->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2127 mono_memory_barrier ();
2129 old_info = klass->runtime_info;
2130 if (old_info && old_info->max_domain >= domain->domain_id) {
2131 /* someone already created a large enough runtime info */
2132 old_info->domain_vtables [domain->domain_id] = vt;
2134 int new_size = domain->domain_id;
2136 new_size = MAX (new_size, old_info->max_domain);
2138 /* make the new size a power of two */
2140 while (new_size > i)
2143 /* this is a bounded memory retention issue: may want to
2144 * handle it differently when we'll have a rcu-like system.
2146 runtime_info = (MonoClassRuntimeInfo *)mono_image_alloc0 (klass->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2147 runtime_info->max_domain = new_size - 1;
2148 /* copy the stuff from the older info */
2150 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2152 runtime_info->domain_vtables [domain->domain_id] = vt;
2154 mono_memory_barrier ();
2155 klass->runtime_info = runtime_info;
2158 if (klass == mono_defaults.runtimetype_class) {
2159 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2160 if (!is_ok (error)) {
2161 mono_domain_unlock (domain);
2162 mono_loader_unlock ();
2166 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2167 /* This is unregistered in
2168 unregister_vtable_reflection_type() in
2170 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2173 mono_domain_unlock (domain);
2174 mono_loader_unlock ();
2176 /* make sure the parent is initialized */
2177 /*FIXME shouldn't this fail the current type?*/
2179 mono_class_vtable_full (domain, klass->parent, error);
2184 #ifndef DISABLE_REMOTING
2186 * mono_class_proxy_vtable:
2187 * @domain: the application domain
2188 * @remove_class: the remote class
2189 * @error: set on error
2191 * Creates a vtable for transparent proxies. It is basically
2192 * a copy of the real vtable of the class wrapped in @remote_class,
2193 * but all function pointers invoke the remoting functions, and
2194 * vtable->klass points to the transparent proxy class, and not to @class.
2196 * On failure returns NULL and sets @error
2199 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type, MonoError *error)
2201 MONO_REQ_GC_UNSAFE_MODE;
2203 MonoVTable *vt, *pvt;
2204 int i, j, vtsize, extra_interface_vtsize = 0;
2205 guint32 max_interface_id;
2207 GSList *extra_interfaces = NULL;
2208 MonoClass *klass = remote_class->proxy_class;
2209 gpointer *interface_offsets;
2210 uint8_t *bitmap = NULL;
2212 size_t imt_table_bytes;
2214 #ifdef COMPRESSED_INTERFACE_BITMAP
2218 mono_error_init (error);
2220 vt = mono_class_vtable (domain, klass);
2221 g_assert (vt); /*FIXME property handle failure*/
2222 max_interface_id = vt->max_interface_id;
2224 /* Calculate vtable space for extra interfaces */
2225 for (j = 0; j < remote_class->interface_count; j++) {
2226 MonoClass* iclass = remote_class->interfaces[j];
2230 /*FIXME test for interfaces with variant generic arguments*/
2231 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, iclass->interface_id))
2232 continue; /* interface implemented by the class */
2233 if (g_slist_find (extra_interfaces, iclass))
2236 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2238 method_count = mono_class_num_methods (iclass);
2240 ifaces = mono_class_get_implemented_interfaces (iclass, error);
2244 for (i = 0; i < ifaces->len; ++i) {
2245 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2246 /*FIXME test for interfaces with variant generic arguments*/
2247 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, ic->interface_id))
2248 continue; /* interface implemented by the class */
2249 if (g_slist_find (extra_interfaces, ic))
2251 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2252 method_count += mono_class_num_methods (ic);
2254 g_ptr_array_free (ifaces, TRUE);
2258 extra_interface_vtsize += method_count * sizeof (gpointer);
2259 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2262 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2263 mono_stats.imt_number_of_tables++;
2264 mono_stats.imt_tables_size += imt_table_bytes;
2266 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer);
2268 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2270 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2271 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2272 g_assert (!((gsize)pvt & 7));
2274 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer));
2276 pvt->klass = mono_defaults.transparent_proxy_class;
2277 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2278 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2280 /* initialize vtable */
2281 mono_class_setup_vtable (klass);
2282 for (i = 0; i < klass->vtable_size; ++i) {
2285 if ((cm = klass->vtable [i])) {
2286 pvt->vtable [i] = create_remoting_trampoline (domain, cm, target_type, error);
2290 pvt->vtable [i] = NULL;
2293 if (mono_class_is_abstract (klass)) {
2294 /* create trampolines for abstract methods */
2295 for (k = klass; k; k = k->parent) {
2297 gpointer iter = NULL;
2298 while ((m = mono_class_get_methods (k, &iter)))
2299 if (!pvt->vtable [m->slot]) {
2300 pvt->vtable [m->slot] = create_remoting_trampoline (domain, m, target_type, error);
2307 pvt->max_interface_id = max_interface_id;
2308 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2309 #ifdef COMPRESSED_INTERFACE_BITMAP
2310 bitmap = (uint8_t *)g_malloc0 (bsize);
2312 bitmap = (uint8_t *)mono_domain_alloc0 (domain, bsize);
2315 for (i = 0; i < klass->interface_offsets_count; ++i) {
2316 int interface_id = klass->interfaces_packed [i]->interface_id;
2317 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2320 if (extra_interfaces) {
2321 int slot = klass->vtable_size;
2327 /* Create trampolines for the methods of the interfaces */
2328 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2329 interf = (MonoClass *)list_item->data;
2331 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2335 while ((cm = mono_class_get_methods (interf, &iter))) {
2336 pvt->vtable [slot + j++] = create_remoting_trampoline (domain, cm, target_type, error);
2341 slot += mono_class_num_methods (interf);
2345 /* Now that the vtable is full, we can actually fill up the IMT */
2346 build_imt (klass, pvt, domain, interface_offsets, extra_interfaces);
2347 if (extra_interfaces) {
2348 g_slist_free (extra_interfaces);
2351 #ifdef COMPRESSED_INTERFACE_BITMAP
2352 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2353 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2354 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2357 pvt->interface_bitmap = bitmap;
2361 if (extra_interfaces)
2362 g_slist_free (extra_interfaces);
2363 #ifdef COMPRESSED_INTERFACE_BITMAP
2369 #endif /* DISABLE_REMOTING */
2372 * mono_class_field_is_special_static:
2374 * Returns whether @field is a thread/context static field.
2377 mono_class_field_is_special_static (MonoClassField *field)
2379 MONO_REQ_GC_NEUTRAL_MODE
2381 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2383 if (mono_field_is_deleted (field))
2385 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2386 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2393 * mono_class_field_get_special_static_type:
2394 * @field: The MonoClassField describing the field.
2396 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2397 * SPECIAL_STATIC_NONE otherwise.
2400 mono_class_field_get_special_static_type (MonoClassField *field)
2402 MONO_REQ_GC_NEUTRAL_MODE
2404 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2405 return SPECIAL_STATIC_NONE;
2406 if (mono_field_is_deleted (field))
2407 return SPECIAL_STATIC_NONE;
2408 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2409 return field_is_special_static (field->parent, field);
2410 return SPECIAL_STATIC_NONE;
2414 * mono_class_has_special_static_fields:
2416 * Returns whenever @klass has any thread/context static fields.
2419 mono_class_has_special_static_fields (MonoClass *klass)
2421 MONO_REQ_GC_NEUTRAL_MODE
2423 MonoClassField *field;
2427 while ((field = mono_class_get_fields (klass, &iter))) {
2428 g_assert (field->parent == klass);
2429 if (mono_class_field_is_special_static (field))
2436 #ifndef DISABLE_REMOTING
2438 * create_remote_class_key:
2439 * Creates an array of pointers that can be used as a hash key for a remote class.
2440 * The first element of the array is the number of pointers.
2443 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2445 MONO_REQ_GC_NEUTRAL_MODE;
2450 if (remote_class == NULL) {
2451 if (mono_class_is_interface (extra_class)) {
2452 key = (void **)g_malloc (sizeof(gpointer) * 3);
2453 key [0] = GINT_TO_POINTER (2);
2454 key [1] = mono_defaults.marshalbyrefobject_class;
2455 key [2] = extra_class;
2457 key = (void **)g_malloc (sizeof(gpointer) * 2);
2458 key [0] = GINT_TO_POINTER (1);
2459 key [1] = extra_class;
2462 if (extra_class != NULL && mono_class_is_interface (extra_class)) {
2463 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2464 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2465 key [1] = remote_class->proxy_class;
2467 // Keep the list of interfaces sorted
2468 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2469 if (extra_class && remote_class->interfaces [i] > extra_class) {
2470 key [j++] = extra_class;
2473 key [j] = remote_class->interfaces [i];
2476 key [j] = extra_class;
2478 // Replace the old class. The interface list is the same
2479 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2480 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2481 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2482 for (i = 0; i < remote_class->interface_count; i++)
2483 key [2 + i] = remote_class->interfaces [i];
2491 * copy_remote_class_key:
2493 * Make a copy of KEY in the domain and return the copy.
2496 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2498 MONO_REQ_GC_NEUTRAL_MODE
2500 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2501 gpointer *mp_key = (gpointer *)mono_domain_alloc (domain, key_size);
2503 memcpy (mp_key, key, key_size);
2509 * mono_remote_class:
2510 * @domain: the application domain
2511 * @class_name: name of the remote class
2512 * @error: set on error
2514 * Creates and initializes a MonoRemoteClass object for a remote type.
2516 * On failure returns NULL and sets @error
2519 mono_remote_class (MonoDomain *domain, MonoStringHandle class_name, MonoClass *proxy_class, MonoError *error)
2521 MONO_REQ_GC_UNSAFE_MODE;
2523 MonoRemoteClass *rc;
2524 gpointer* key, *mp_key;
2527 mono_error_init (error);
2529 key = create_remote_class_key (NULL, proxy_class);
2531 mono_domain_lock (domain);
2532 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2536 mono_domain_unlock (domain);
2540 name = mono_string_to_utf8_mp (domain->mp, MONO_HANDLE_RAW (class_name), error);
2541 if (!is_ok (error)) {
2543 mono_domain_unlock (domain);
2547 mp_key = copy_remote_class_key (domain, key);
2551 if (mono_class_is_interface (proxy_class)) {
2552 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2553 rc->interface_count = 1;
2554 rc->interfaces [0] = proxy_class;
2555 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2557 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2558 rc->interface_count = 0;
2559 rc->proxy_class = proxy_class;
2562 rc->default_vtable = NULL;
2563 rc->xdomain_vtable = NULL;
2564 rc->proxy_class_name = name;
2565 #ifndef DISABLE_PERFCOUNTERS
2566 mono_perfcounters->loader_bytes += mono_string_length (MONO_HANDLE_RAW (class_name)) + 1;
2569 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2571 mono_domain_unlock (domain);
2576 * clone_remote_class:
2577 * Creates a copy of the remote_class, adding the provided class or interface
2579 static MonoRemoteClass*
2580 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2582 MONO_REQ_GC_NEUTRAL_MODE;
2584 MonoRemoteClass *rc;
2585 gpointer* key, *mp_key;
2587 key = create_remote_class_key (remote_class, extra_class);
2588 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2594 mp_key = copy_remote_class_key (domain, key);
2598 if (mono_class_is_interface (extra_class)) {
2600 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2601 rc->proxy_class = remote_class->proxy_class;
2602 rc->interface_count = remote_class->interface_count + 1;
2604 // Keep the list of interfaces sorted, since the hash key of
2605 // the remote class depends on this
2606 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2607 if (remote_class->interfaces [i] > extra_class && i == j)
2608 rc->interfaces [j++] = extra_class;
2609 rc->interfaces [j] = remote_class->interfaces [i];
2612 rc->interfaces [j] = extra_class;
2614 // Replace the old class. The interface array is the same
2615 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2616 rc->proxy_class = extra_class;
2617 rc->interface_count = remote_class->interface_count;
2618 if (rc->interface_count > 0)
2619 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2622 rc->default_vtable = NULL;
2623 rc->xdomain_vtable = NULL;
2624 rc->proxy_class_name = remote_class->proxy_class_name;
2626 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2632 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxyHandle rp, MonoError *error)
2634 MONO_REQ_GC_UNSAFE_MODE;
2636 mono_error_init (error);
2638 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2639 mono_domain_lock (domain);
2640 gint32 target_domain_id = MONO_HANDLE_GETVAL (rp, target_domain_id);
2641 if (target_domain_id != -1) {
2642 if (remote_class->xdomain_vtable == NULL)
2643 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN, error);
2644 mono_domain_unlock (domain);
2645 mono_loader_unlock ();
2646 return_val_if_nok (error, NULL);
2647 return remote_class->xdomain_vtable;
2649 if (remote_class->default_vtable == NULL) {
2650 MonoReflectionTypeHandle reftype = MONO_HANDLE_NEW (MonoReflectionType, NULL);
2651 MONO_HANDLE_GET (reftype, rp, class_to_proxy);
2653 MonoType *type = MONO_HANDLE_GETVAL (reftype, type);
2654 MonoClass *klass = mono_class_from_mono_type (type);
2656 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)))
2657 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP, error);
2660 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN, error);
2661 /* N.B. both branches of the if modify error */
2662 if (!is_ok (error)) {
2663 mono_domain_unlock (domain);
2664 mono_loader_unlock ();
2669 mono_domain_unlock (domain);
2670 mono_loader_unlock ();
2671 return remote_class->default_vtable;
2675 * mono_upgrade_remote_class:
2676 * @domain: the application domain
2677 * @tproxy: the proxy whose remote class has to be upgraded.
2678 * @klass: class to which the remote class can be casted.
2679 * @error: set on error
2681 * Updates the vtable of the remote class by adding the necessary method slots
2682 * and interface offsets so it can be safely casted to klass. klass can be a
2683 * class or an interface. On success returns TRUE, on failure returns FALSE and sets @error.
2686 mono_upgrade_remote_class (MonoDomain *domain, MonoObjectHandle proxy_object, MonoClass *klass, MonoError *error)
2688 MONO_REQ_GC_UNSAFE_MODE;
2690 mono_error_init (error);
2692 MonoTransparentProxyHandle tproxy = MONO_HANDLE_CAST (MonoTransparentProxy, proxy_object);
2693 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (tproxy, remote_class);
2695 gboolean redo_vtable;
2696 if (mono_class_is_interface (klass)) {
2699 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2700 if (remote_class->interfaces [i] == klass)
2701 redo_vtable = FALSE;
2704 redo_vtable = (remote_class->proxy_class != klass);
2707 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2708 mono_domain_lock (domain);
2710 MonoRemoteClass *fresh_remote_class = clone_remote_class (domain, remote_class, klass);
2711 MONO_HANDLE_SETVAL (tproxy, remote_class, MonoRemoteClass*, fresh_remote_class);
2712 MonoRealProxyHandle real_proxy = MONO_HANDLE_NEW (MonoRealProxy, NULL);
2713 MONO_HANDLE_GET (real_proxy, tproxy, rp);
2714 MONO_HANDLE_SETVAL (proxy_object, vtable, MonoVTable*, mono_remote_class_vtable (domain, fresh_remote_class, real_proxy, error));
2720 mono_domain_unlock (domain);
2721 mono_loader_unlock ();
2722 return is_ok (error);
2724 #endif /* DISABLE_REMOTING */
2728 * mono_object_get_virtual_method:
2729 * @obj: object to operate on.
2732 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2733 * the instance of a callvirt of method.
2736 mono_object_get_virtual_method (MonoObject *obj_raw, MonoMethod *method)
2738 MONO_REQ_GC_UNSAFE_MODE;
2739 HANDLE_FUNCTION_ENTER ();
2741 MONO_HANDLE_DCL (MonoObject, obj);
2742 MonoMethod *result = mono_object_handle_get_virtual_method (obj, method, &error);
2743 mono_error_assert_ok (&error);
2744 HANDLE_FUNCTION_RETURN_VAL (result);
2748 * mono_object_get_virtual_method:
2749 * @obj: object to operate on.
2752 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2753 * the instance of a callvirt of method.
2756 mono_object_handle_get_virtual_method (MonoObjectHandle obj, MonoMethod *method, MonoError *error)
2758 mono_error_init (error);
2760 gboolean is_proxy = FALSE;
2761 MonoClass *klass = mono_handle_class (obj);
2762 if (mono_class_is_transparent_proxy (klass)) {
2763 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), remote_class);
2764 klass = remote_class->proxy_class;
2767 return class_get_virtual_method (klass, method, is_proxy, error);
2771 class_get_virtual_method (MonoClass *klass, MonoMethod *method, gboolean is_proxy, MonoError *error)
2773 mono_error_init (error);
2776 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2779 mono_class_setup_vtable (klass);
2780 MonoMethod **vtable = klass->vtable;
2782 if (method->slot == -1) {
2783 /* method->slot might not be set for instances of generic methods */
2784 if (method->is_inflated) {
2785 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2786 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2789 g_assert_not_reached ();
2793 MonoMethod *res = NULL;
2794 /* check method->slot is a valid index: perform isinstance? */
2795 if (method->slot != -1) {
2796 if (mono_class_is_interface (method->klass)) {
2798 gboolean variance_used = FALSE;
2799 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2800 g_assert (iface_offset > 0);
2801 res = vtable [iface_offset + method->slot];
2804 res = vtable [method->slot];
2808 #ifndef DISABLE_REMOTING
2810 /* It may be an interface, abstract class method or generic method */
2811 if (!res || mono_method_signature (res)->generic_param_count)
2814 /* generic methods demand invoke_with_check */
2815 if (mono_method_signature (res)->generic_param_count)
2816 res = mono_marshal_get_remoting_invoke_with_check (res);
2819 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2820 res = mono_cominterop_get_invoke (res);
2823 res = mono_marshal_get_remoting_invoke (res);
2828 if (method->is_inflated) {
2829 /* Have to inflate the result */
2830 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, error);
2838 do_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2840 MONO_REQ_GC_UNSAFE_MODE;
2842 MonoObject *result = NULL;
2844 g_assert (callbacks.runtime_invoke);
2846 mono_error_init (error);
2848 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2849 mono_profiler_method_start_invoke (method);
2851 result = callbacks.runtime_invoke (method, obj, params, exc, error);
2853 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2854 mono_profiler_method_end_invoke (method);
2856 if (!mono_error_ok (error))
2863 * mono_runtime_invoke:
2864 * @method: method to invoke
2865 * @obJ: object instance
2866 * @params: arguments to the method
2867 * @exc: exception information.
2869 * Invokes the method represented by @method on the object @obj.
2871 * obj is the 'this' pointer, it should be NULL for static
2872 * methods, a MonoObject* for object instances and a pointer to
2873 * the value type for value types.
2875 * The params array contains the arguments to the method with the
2876 * same convention: MonoObject* pointers for object instances and
2877 * pointers to the value type otherwise.
2879 * From unmanaged code you'll usually use the
2880 * mono_runtime_invoke() variant.
2882 * Note that this function doesn't handle virtual methods for
2883 * you, it will exec the exact method you pass: we still need to
2884 * expose a function to lookup the derived class implementation
2885 * of a virtual method (there are examples of this in the code,
2888 * You can pass NULL as the exc argument if you don't want to
2889 * catch exceptions, otherwise, *exc will be set to the exception
2890 * thrown, if any. if an exception is thrown, you can't use the
2891 * MonoObject* result from the function.
2893 * If the method returns a value type, it is boxed in an object
2897 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2902 res = mono_runtime_try_invoke (method, obj, params, exc, &error);
2903 if (*exc == NULL && !mono_error_ok(&error)) {
2904 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
2906 mono_error_cleanup (&error);
2908 res = mono_runtime_invoke_checked (method, obj, params, &error);
2909 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
2915 * mono_runtime_try_invoke:
2916 * @method: method to invoke
2917 * @obJ: object instance
2918 * @params: arguments to the method
2919 * @exc: exception information.
2920 * @error: set on error
2922 * Invokes the method represented by @method on the object @obj.
2924 * obj is the 'this' pointer, it should be NULL for static
2925 * methods, a MonoObject* for object instances and a pointer to
2926 * the value type for value types.
2928 * The params array contains the arguments to the method with the
2929 * same convention: MonoObject* pointers for object instances and
2930 * pointers to the value type otherwise.
2932 * From unmanaged code you'll usually use the
2933 * mono_runtime_invoke() variant.
2935 * Note that this function doesn't handle virtual methods for
2936 * you, it will exec the exact method you pass: we still need to
2937 * expose a function to lookup the derived class implementation
2938 * of a virtual method (there are examples of this in the code,
2941 * For this function, you must not pass NULL as the exc argument if
2942 * you don't want to catch exceptions, use
2943 * mono_runtime_invoke_checked(). If an exception is thrown, you
2944 * can't use the MonoObject* result from the function.
2946 * If this method cannot be invoked, @error will be set and @exc and
2947 * the return value must not be used.
2949 * If the method returns a value type, it is boxed in an object
2953 mono_runtime_try_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError* error)
2955 MONO_REQ_GC_UNSAFE_MODE;
2957 g_assert (exc != NULL);
2959 if (mono_runtime_get_no_exec ())
2960 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2962 return do_runtime_invoke (method, obj, params, exc, error);
2966 * mono_runtime_invoke_checked:
2967 * @method: method to invoke
2968 * @obJ: object instance
2969 * @params: arguments to the method
2970 * @error: set on error
2972 * Invokes the method represented by @method on the object @obj.
2974 * obj is the 'this' pointer, it should be NULL for static
2975 * methods, a MonoObject* for object instances and a pointer to
2976 * the value type for value types.
2978 * The params array contains the arguments to the method with the
2979 * same convention: MonoObject* pointers for object instances and
2980 * pointers to the value type otherwise.
2982 * From unmanaged code you'll usually use the
2983 * mono_runtime_invoke() variant.
2985 * Note that this function doesn't handle virtual methods for
2986 * you, it will exec the exact method you pass: we still need to
2987 * expose a function to lookup the derived class implementation
2988 * of a virtual method (there are examples of this in the code,
2991 * If an exception is thrown, you can't use the MonoObject* result
2992 * from the function.
2994 * If this method cannot be invoked, @error will be set. If the
2995 * method throws an exception (and we're in coop mode) the exception
2996 * will be set in @error.
2998 * If the method returns a value type, it is boxed in an object
3002 mono_runtime_invoke_checked (MonoMethod *method, void *obj, void **params, MonoError* error)
3004 MONO_REQ_GC_UNSAFE_MODE;
3006 if (mono_runtime_get_no_exec ())
3007 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
3009 return do_runtime_invoke (method, obj, params, NULL, error);
3013 * mono_method_get_unmanaged_thunk:
3014 * @method: method to generate a thunk for.
3016 * Returns an unmanaged->managed thunk that can be used to call
3017 * a managed method directly from C.
3019 * The thunk's C signature closely matches the managed signature:
3021 * C#: public bool Equals (object obj);
3022 * C: typedef MonoBoolean (*Equals)(MonoObject*,
3023 * MonoObject*, MonoException**);
3025 * The 1st ("this") parameter must not be used with static methods:
3027 * C#: public static bool ReferenceEquals (object a, object b);
3028 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
3031 * The last argument must be a non-null pointer of a MonoException* pointer.
3032 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
3033 * exception has been thrown in managed code. Otherwise it will point
3034 * to the MonoException* caught by the thunk. In this case, the result of
3035 * the thunk is undefined:
3037 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
3038 * MonoException *ex = NULL;
3039 * Equals func = mono_method_get_unmanaged_thunk (method);
3040 * MonoBoolean res = func (thisObj, objToCompare, &ex);
3042 * // handle exception
3045 * The calling convention of the thunk matches the platform's default
3046 * convention. This means that under Windows, C declarations must
3047 * contain the __stdcall attribute:
3049 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
3050 * MonoObject*, MonoException**);
3054 * Value type arguments and return values are treated as they were objects:
3056 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
3057 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
3059 * Arguments must be properly boxed upon trunk's invocation, while return
3060 * values must be unboxed.
3063 mono_method_get_unmanaged_thunk (MonoMethod *method)
3065 MONO_REQ_GC_NEUTRAL_MODE;
3066 MONO_REQ_API_ENTRYPOINT;
3071 g_assert (!mono_threads_is_coop_enabled ());
3073 MONO_ENTER_GC_UNSAFE;
3074 method = mono_marshal_get_thunk_invoke_wrapper (method);
3075 res = mono_compile_method_checked (method, &error);
3076 mono_error_cleanup (&error);
3077 MONO_EXIT_GC_UNSAFE;
3083 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
3085 MONO_REQ_GC_UNSAFE_MODE;
3089 /* object fields cannot be byref, so we don't need a
3091 gpointer *p = (gpointer*)dest;
3098 case MONO_TYPE_BOOLEAN:
3100 case MONO_TYPE_U1: {
3101 guint8 *p = (guint8*)dest;
3102 *p = value ? *(guint8*)value : 0;
3107 case MONO_TYPE_CHAR: {
3108 guint16 *p = (guint16*)dest;
3109 *p = value ? *(guint16*)value : 0;
3112 #if SIZEOF_VOID_P == 4
3117 case MONO_TYPE_U4: {
3118 gint32 *p = (gint32*)dest;
3119 *p = value ? *(gint32*)value : 0;
3122 #if SIZEOF_VOID_P == 8
3127 case MONO_TYPE_U8: {
3128 gint64 *p = (gint64*)dest;
3129 *p = value ? *(gint64*)value : 0;
3132 case MONO_TYPE_R4: {
3133 float *p = (float*)dest;
3134 *p = value ? *(float*)value : 0;
3137 case MONO_TYPE_R8: {
3138 double *p = (double*)dest;
3139 *p = value ? *(double*)value : 0;
3142 case MONO_TYPE_STRING:
3143 case MONO_TYPE_SZARRAY:
3144 case MONO_TYPE_CLASS:
3145 case MONO_TYPE_OBJECT:
3146 case MONO_TYPE_ARRAY:
3147 mono_gc_wbarrier_generic_store (dest, deref_pointer ? *(MonoObject **)value : (MonoObject *)value);
3149 case MONO_TYPE_FNPTR:
3150 case MONO_TYPE_PTR: {
3151 gpointer *p = (gpointer*)dest;
3152 *p = deref_pointer? *(gpointer*)value: value;
3155 case MONO_TYPE_VALUETYPE:
3156 /* note that 't' and 'type->type' can be different */
3157 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3158 t = mono_class_enum_basetype (type->data.klass)->type;
3161 MonoClass *klass = mono_class_from_mono_type (type);
3162 int size = mono_class_value_size (klass, NULL);
3164 mono_gc_bzero_atomic (dest, size);
3166 mono_gc_wbarrier_value_copy (dest, value, 1, klass);
3169 case MONO_TYPE_GENERICINST:
3170 t = type->data.generic_class->container_class->byval_arg.type;
3173 g_error ("got type %x", type->type);
3178 * mono_field_set_value:
3179 * @obj: Instance object
3180 * @field: MonoClassField describing the field to set
3181 * @value: The value to be set
3183 * Sets the value of the field described by @field in the object instance @obj
3184 * to the value passed in @value. This method should only be used for instance
3185 * fields. For static fields, use mono_field_static_set_value.
3187 * The value must be on the native format of the field type.
3190 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3192 MONO_REQ_GC_UNSAFE_MODE;
3196 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3198 dest = (char*)obj + field->offset;
3199 mono_copy_value (field->type, dest, value, FALSE);
3203 * mono_field_static_set_value:
3204 * @field: MonoClassField describing the field to set
3205 * @value: The value to be set
3207 * Sets the value of the static field described by @field
3208 * to the value passed in @value.
3210 * The value must be on the native format of the field type.
3213 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3215 MONO_REQ_GC_UNSAFE_MODE;
3219 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3220 /* you cant set a constant! */
3221 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3223 if (field->offset == -1) {
3224 /* Special static */
3227 mono_domain_lock (vt->domain);
3228 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3229 mono_domain_unlock (vt->domain);
3230 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3232 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3234 mono_copy_value (field->type, dest, value, FALSE);
3238 * mono_vtable_get_static_field_data:
3240 * Internal use function: return a pointer to the memory holding the static fields
3241 * for a class or NULL if there are no static fields.
3242 * This is exported only for use by the debugger.
3245 mono_vtable_get_static_field_data (MonoVTable *vt)
3247 MONO_REQ_GC_NEUTRAL_MODE
3249 if (!vt->has_static_fields)
3251 return vt->vtable [vt->klass->vtable_size];
3255 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3257 MONO_REQ_GC_UNSAFE_MODE;
3261 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3262 if (field->offset == -1) {
3263 /* Special static */
3266 mono_domain_lock (vt->domain);
3267 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3268 mono_domain_unlock (vt->domain);
3269 src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3271 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3274 src = (guint8*)obj + field->offset;
3281 * mono_field_get_value:
3282 * @obj: Object instance
3283 * @field: MonoClassField describing the field to fetch information from
3284 * @value: pointer to the location where the value will be stored
3286 * Use this routine to get the value of the field @field in the object
3289 * The pointer provided by value must be of the field type, for reference
3290 * types this is a MonoObject*, for value types its the actual pointer to
3295 * mono_field_get_value (obj, int_field, &i);
3298 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3300 MONO_REQ_GC_UNSAFE_MODE;
3306 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3308 src = (char*)obj + field->offset;
3309 mono_copy_value (field->type, value, src, TRUE);
3313 * mono_field_get_value_object:
3314 * @domain: domain where the object will be created (if boxing)
3315 * @field: MonoClassField describing the field to fetch information from
3316 * @obj: The object instance for the field.
3318 * Returns: a new MonoObject with the value from the given field. If the
3319 * field represents a value type, the value is boxed.
3323 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3326 MonoObject* result = mono_field_get_value_object_checked (domain, field, obj, &error);
3327 mono_error_assert_ok (&error);
3332 * mono_field_get_value_object_checked:
3333 * @domain: domain where the object will be created (if boxing)
3334 * @field: MonoClassField describing the field to fetch information from
3335 * @obj: The object instance for the field.
3336 * @error: Set on error.
3338 * Returns: a new MonoObject with the value from the given field. If the
3339 * field represents a value type, the value is boxed. On error returns NULL and sets @error.
3343 mono_field_get_value_object_checked (MonoDomain *domain, MonoClassField *field, MonoObject *obj, MonoError *error)
3345 MONO_REQ_GC_UNSAFE_MODE;
3347 mono_error_init (error);
3351 MonoVTable *vtable = NULL;
3353 gboolean is_static = FALSE;
3354 gboolean is_ref = FALSE;
3355 gboolean is_literal = FALSE;
3356 gboolean is_ptr = FALSE;
3357 MonoType *type = mono_field_get_type_checked (field, error);
3359 return_val_if_nok (error, NULL);
3361 switch (type->type) {
3362 case MONO_TYPE_STRING:
3363 case MONO_TYPE_OBJECT:
3364 case MONO_TYPE_CLASS:
3365 case MONO_TYPE_ARRAY:
3366 case MONO_TYPE_SZARRAY:
3371 case MONO_TYPE_BOOLEAN:
3374 case MONO_TYPE_CHAR:
3383 case MONO_TYPE_VALUETYPE:
3384 is_ref = type->byref;
3386 case MONO_TYPE_GENERICINST:
3387 is_ref = !mono_type_generic_inst_is_valuetype (type);
3393 g_error ("type 0x%x not handled in "
3394 "mono_field_get_value_object", type->type);
3398 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3401 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3405 vtable = mono_class_vtable_full (domain, field->parent, error);
3406 return_val_if_nok (error, NULL);
3408 if (!vtable->initialized) {
3409 mono_runtime_class_init_full (vtable, error);
3410 return_val_if_nok (error, NULL);
3419 get_default_field_value (domain, field, &o, error);
3420 return_val_if_nok (error, NULL);
3421 } else if (is_static) {
3422 mono_field_static_get_value_checked (vtable, field, &o, error);
3423 return_val_if_nok (error, NULL);
3425 mono_field_get_value (obj, field, &o);
3431 static MonoMethod *m;
3437 MonoClass *ptr_klass = mono_class_get_pointer_class ();
3438 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3444 get_default_field_value (domain, field, v, error);
3445 return_val_if_nok (error, NULL);
3446 } else if (is_static) {
3447 mono_field_static_get_value_checked (vtable, field, v, error);
3448 return_val_if_nok (error, NULL);
3450 mono_field_get_value (obj, field, v);
3453 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3454 args [0] = ptr ? *ptr : NULL;
3455 args [1] = mono_type_get_object_checked (mono_domain_get (), type, error);
3456 return_val_if_nok (error, NULL);
3458 o = mono_runtime_invoke_checked (m, NULL, args, error);
3459 return_val_if_nok (error, NULL);
3464 /* boxed value type */
3465 klass = mono_class_from_mono_type (type);
3467 if (mono_class_is_nullable (klass))
3468 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass, error);
3470 o = mono_object_new_checked (domain, klass, error);
3471 return_val_if_nok (error, NULL);
3472 v = ((gchar *) o) + sizeof (MonoObject);
3475 get_default_field_value (domain, field, v, error);
3476 return_val_if_nok (error, NULL);
3477 } else if (is_static) {
3478 mono_field_static_get_value_checked (vtable, field, v, error);
3479 return_val_if_nok (error, NULL);
3481 mono_field_get_value (obj, field, v);
3488 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value, MonoError *error)
3490 MONO_REQ_GC_UNSAFE_MODE;
3492 mono_error_init (error);
3494 const char *p = blob;
3495 mono_metadata_decode_blob_size (p, &p);
3498 case MONO_TYPE_BOOLEAN:
3501 *(guint8 *) value = *p;
3503 case MONO_TYPE_CHAR:
3506 *(guint16*) value = read16 (p);
3510 *(guint32*) value = read32 (p);
3514 *(guint64*) value = read64 (p);
3517 readr4 (p, (float*) value);
3520 readr8 (p, (double*) value);
3522 case MONO_TYPE_STRING:
3523 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob, error);
3525 case MONO_TYPE_CLASS:
3526 *(gpointer*) value = NULL;
3530 g_warning ("type 0x%02x should not be in constant table", type);
3536 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error)
3538 MONO_REQ_GC_NEUTRAL_MODE;
3540 MonoTypeEnum def_type;
3543 mono_error_init (error);
3545 data = mono_class_get_field_default_value (field, &def_type);
3546 mono_get_constant_value_from_blob (domain, def_type, data, value, error);
3550 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3552 MONO_REQ_GC_UNSAFE_MODE;
3556 mono_error_init (error);
3558 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3560 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3561 get_default_field_value (vt->domain, field, value, error);
3565 if (field->offset == -1) {
3566 /* Special static */
3567 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3568 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3570 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3572 mono_copy_value (field->type, value, src, TRUE);
3576 * mono_field_static_get_value:
3577 * @vt: vtable to the object
3578 * @field: MonoClassField describing the field to fetch information from
3579 * @value: where the value is returned
3581 * Use this routine to get the value of the static field @field value.
3583 * The pointer provided by value must be of the field type, for reference
3584 * types this is a MonoObject*, for value types its the actual pointer to
3589 * mono_field_static_get_value (vt, int_field, &i);
3592 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3594 MONO_REQ_GC_NEUTRAL_MODE;
3597 mono_field_static_get_value_checked (vt, field, value, &error);
3598 mono_error_cleanup (&error);
3602 * mono_field_static_get_value_checked:
3603 * @vt: vtable to the object
3604 * @field: MonoClassField describing the field to fetch information from
3605 * @value: where the value is returned
3606 * @error: set on error
3608 * Use this routine to get the value of the static field @field value.
3610 * The pointer provided by value must be of the field type, for reference
3611 * types this is a MonoObject*, for value types its the actual pointer to
3616 * mono_field_static_get_value_checked (vt, int_field, &i, error);
3617 * if (!is_ok (error)) { ... }
3619 * On failure sets @error.
3622 mono_field_static_get_value_checked (MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3624 MONO_REQ_GC_NEUTRAL_MODE;
3626 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value, error);
3630 * mono_property_set_value:
3631 * @prop: MonoProperty to set
3632 * @obj: instance object on which to act
3633 * @params: parameters to pass to the propery
3634 * @exc: optional exception
3636 * Invokes the property's set method with the given arguments on the
3637 * object instance obj (or NULL for static properties).
3639 * You can pass NULL as the exc argument if you don't want to
3640 * catch exceptions, otherwise, *exc will be set to the exception
3641 * thrown, if any. if an exception is thrown, you can't use the
3642 * MonoObject* result from the function.
3645 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3647 MONO_REQ_GC_UNSAFE_MODE;
3650 do_runtime_invoke (prop->set, obj, params, exc, &error);
3651 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3652 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3654 mono_error_cleanup (&error);
3659 * mono_property_set_value_checked:
3660 * @prop: MonoProperty to set
3661 * @obj: instance object on which to act
3662 * @params: parameters to pass to the propery
3663 * @error: set on error
3665 * Invokes the property's set method with the given arguments on the
3666 * object instance obj (or NULL for static properties).
3668 * Returns: TRUE on success. On failure returns FALSE and sets @error.
3669 * If an exception is thrown, it will be caught and returned via @error.
3672 mono_property_set_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3674 MONO_REQ_GC_UNSAFE_MODE;
3678 mono_error_init (error);
3679 do_runtime_invoke (prop->set, obj, params, &exc, error);
3680 if (exc != NULL && is_ok (error))
3681 mono_error_set_exception_instance (error, (MonoException*)exc);
3682 return is_ok (error);
3686 * mono_property_get_value:
3687 * @prop: MonoProperty to fetch
3688 * @obj: instance object on which to act
3689 * @params: parameters to pass to the propery
3690 * @exc: optional exception
3692 * Invokes the property's get method with the given arguments on the
3693 * object instance obj (or NULL for static properties).
3695 * You can pass NULL as the exc argument if you don't want to
3696 * catch exceptions, otherwise, *exc will be set to the exception
3697 * thrown, if any. if an exception is thrown, you can't use the
3698 * MonoObject* result from the function.
3700 * Returns: the value from invoking the get method on the property.
3703 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3705 MONO_REQ_GC_UNSAFE_MODE;
3708 MonoObject *val = do_runtime_invoke (prop->get, obj, params, exc, &error);
3709 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3710 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3712 mono_error_cleanup (&error); /* FIXME don't raise here */
3719 * mono_property_get_value_checked:
3720 * @prop: MonoProperty to fetch
3721 * @obj: instance object on which to act
3722 * @params: parameters to pass to the propery
3723 * @error: set on error
3725 * Invokes the property's get method with the given arguments on the
3726 * object instance obj (or NULL for static properties).
3728 * If an exception is thrown, you can't use the
3729 * MonoObject* result from the function. The exception will be propagated via @error.
3731 * Returns: the value from invoking the get method on the property. On
3732 * failure returns NULL and sets @error.
3735 mono_property_get_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3737 MONO_REQ_GC_UNSAFE_MODE;
3740 MonoObject *val = do_runtime_invoke (prop->get, obj, params, &exc, error);
3741 if (exc != NULL && !is_ok (error))
3742 mono_error_set_exception_instance (error, (MonoException*) exc);
3750 * mono_nullable_init:
3751 * @buf: The nullable structure to initialize.
3752 * @value: the value to initialize from
3753 * @klass: the type for the object
3755 * Initialize the nullable structure pointed to by @buf from @value which
3756 * should be a boxed value type. The size of @buf should be able to hold
3757 * as much data as the @klass->instance_size (which is the number of bytes
3758 * that will be copies).
3760 * Since Nullables have variable structure, we can not define a C
3761 * structure for them.
3764 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3766 MONO_REQ_GC_UNSAFE_MODE;
3768 MonoClass *param_class = klass->cast_class;
3770 mono_class_setup_fields (klass);
3771 g_assert (klass->fields_inited);
3773 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3774 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3776 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3778 if (param_class->has_references)
3779 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3781 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3783 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3788 * mono_nullable_box:
3789 * @buf: The buffer representing the data to be boxed
3790 * @klass: the type to box it as.
3791 * @error: set on oerr
3793 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3794 * @buf. On failure returns NULL and sets @error
3797 mono_nullable_box (guint8 *buf, MonoClass *klass, MonoError *error)
3799 MONO_REQ_GC_UNSAFE_MODE;
3801 mono_error_init (error);
3802 MonoClass *param_class = klass->cast_class;
3804 mono_class_setup_fields (klass);
3805 g_assert (klass->fields_inited);
3807 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3808 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3810 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3811 MonoObject *o = mono_object_new_checked (mono_domain_get (), param_class, error);
3812 return_val_if_nok (error, NULL);
3813 if (param_class->has_references)
3814 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3816 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3824 * mono_get_delegate_invoke:
3825 * @klass: The delegate class
3827 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3830 mono_get_delegate_invoke (MonoClass *klass)
3832 MONO_REQ_GC_NEUTRAL_MODE;
3836 /* This is called at runtime, so avoid the slower search in metadata */
3837 mono_class_setup_methods (klass);
3838 if (mono_class_has_failure (klass))
3840 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3845 * mono_get_delegate_begin_invoke:
3846 * @klass: The delegate class
3848 * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3851 mono_get_delegate_begin_invoke (MonoClass *klass)
3853 MONO_REQ_GC_NEUTRAL_MODE;
3857 /* This is called at runtime, so avoid the slower search in metadata */
3858 mono_class_setup_methods (klass);
3859 if (mono_class_has_failure (klass))
3861 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3866 * mono_get_delegate_end_invoke:
3867 * @klass: The delegate class
3869 * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3872 mono_get_delegate_end_invoke (MonoClass *klass)
3874 MONO_REQ_GC_NEUTRAL_MODE;
3878 /* This is called at runtime, so avoid the slower search in metadata */
3879 mono_class_setup_methods (klass);
3880 if (mono_class_has_failure (klass))
3882 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3887 * mono_runtime_delegate_invoke:
3888 * @delegate: pointer to a delegate object.
3889 * @params: parameters for the delegate.
3890 * @exc: Pointer to the exception result.
3892 * Invokes the delegate method @delegate with the parameters provided.
3894 * You can pass NULL as the exc argument if you don't want to
3895 * catch exceptions, otherwise, *exc will be set to the exception
3896 * thrown, if any. if an exception is thrown, you can't use the
3897 * MonoObject* result from the function.
3900 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3902 MONO_REQ_GC_UNSAFE_MODE;
3906 MonoObject *result = mono_runtime_delegate_try_invoke (delegate, params, exc, &error);
3908 mono_error_cleanup (&error);
3911 if (!is_ok (&error))
3912 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
3916 MonoObject *result = mono_runtime_delegate_invoke_checked (delegate, params, &error);
3917 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
3923 * mono_runtime_delegate_try_invoke:
3924 * @delegate: pointer to a delegate object.
3925 * @params: parameters for the delegate.
3926 * @exc: Pointer to the exception result.
3927 * @error: set on error
3929 * Invokes the delegate method @delegate with the parameters provided.
3931 * You can pass NULL as the exc argument if you don't want to
3932 * catch exceptions, otherwise, *exc will be set to the exception
3933 * thrown, if any. On failure to execute, @error will be set.
3934 * if an exception is thrown, you can't use the
3935 * MonoObject* result from the function.
3938 mono_runtime_delegate_try_invoke (MonoObject *delegate, void **params, MonoObject **exc, MonoError *error)
3940 MONO_REQ_GC_UNSAFE_MODE;
3942 mono_error_init (error);
3944 MonoClass *klass = delegate->vtable->klass;
3947 im = mono_get_delegate_invoke (klass);
3949 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3952 o = mono_runtime_try_invoke (im, delegate, params, exc, error);
3954 o = mono_runtime_invoke_checked (im, delegate, params, error);
3961 * mono_runtime_delegate_invoke_checked:
3962 * @delegate: pointer to a delegate object.
3963 * @params: parameters for the delegate.
3964 * @error: set on error
3966 * Invokes the delegate method @delegate with the parameters provided.
3968 * On failure @error will be set and you can't use the MonoObject*
3969 * result from the function.
3972 mono_runtime_delegate_invoke_checked (MonoObject *delegate, void **params, MonoError *error)
3974 mono_error_init (error);
3975 return mono_runtime_delegate_try_invoke (delegate, params, NULL, error);
3978 static char **main_args = NULL;
3979 static int num_main_args = 0;
3982 * mono_runtime_get_main_args:
3984 * Returns: a MonoArray with the arguments passed to the main program
3987 mono_runtime_get_main_args (void)
3989 MONO_REQ_GC_UNSAFE_MODE;
3991 MonoArray *result = mono_runtime_get_main_args_checked (&error);
3992 mono_error_assert_ok (&error);
3997 * mono_runtime_get_main_args:
3998 * @error: set on error
4000 * Returns: a MonoArray with the arguments passed to the main
4001 * program. On failure returns NULL and sets @error.
4004 mono_runtime_get_main_args_checked (MonoError *error)
4008 MonoDomain *domain = mono_domain_get ();
4010 mono_error_init (error);
4012 res = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, num_main_args, error);
4013 return_val_if_nok (error, NULL);
4015 for (i = 0; i < num_main_args; ++i)
4016 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
4022 free_main_args (void)
4024 MONO_REQ_GC_NEUTRAL_MODE;
4028 for (i = 0; i < num_main_args; ++i)
4029 g_free (main_args [i]);
4036 * mono_runtime_set_main_args:
4037 * @argc: number of arguments from the command line
4038 * @argv: array of strings from the command line
4040 * Set the command line arguments from an embedding application that doesn't otherwise call
4041 * mono_runtime_run_main ().
4044 mono_runtime_set_main_args (int argc, char* argv[])
4046 MONO_REQ_GC_NEUTRAL_MODE;
4051 main_args = g_new0 (char*, argc);
4052 num_main_args = argc;
4054 for (i = 0; i < argc; ++i) {
4057 utf8_arg = mono_utf8_from_external (argv[i]);
4058 if (utf8_arg == NULL) {
4059 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
4060 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4064 main_args [i] = utf8_arg;
4071 * Prepare an array of arguments in order to execute a standard Main()
4072 * method (argc/argv contains the executable name). This method also
4073 * sets the command line argument value needed by System.Environment.
4077 prepare_run_main (MonoMethod *method, int argc, char *argv[])
4079 MONO_REQ_GC_UNSAFE_MODE;
4083 MonoArray *args = NULL;
4084 MonoDomain *domain = mono_domain_get ();
4085 gchar *utf8_fullpath;
4086 MonoMethodSignature *sig;
4088 g_assert (method != NULL);
4090 mono_thread_set_main (mono_thread_current ());
4092 main_args = g_new0 (char*, argc);
4093 num_main_args = argc;
4095 if (!g_path_is_absolute (argv [0])) {
4096 gchar *basename = g_path_get_basename (argv [0]);
4097 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
4101 utf8_fullpath = mono_utf8_from_external (fullpath);
4102 if(utf8_fullpath == NULL) {
4103 /* Printing the arg text will cause glib to
4104 * whinge about "Invalid UTF-8", but at least
4105 * its relevant, and shows the problem text
4108 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
4109 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4116 utf8_fullpath = mono_utf8_from_external (argv[0]);
4117 if(utf8_fullpath == NULL) {
4118 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
4119 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4124 main_args [0] = utf8_fullpath;
4126 for (i = 1; i < argc; ++i) {
4129 utf8_arg=mono_utf8_from_external (argv[i]);
4130 if(utf8_arg==NULL) {
4131 /* Ditto the comment about Invalid UTF-8 here */
4132 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
4133 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4137 main_args [i] = utf8_arg;
4142 sig = mono_method_signature (method);
4144 g_print ("Unable to load Main method.\n");
4148 if (sig->param_count) {
4149 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, argc, &error);
4150 mono_error_assert_ok (&error);
4151 for (i = 0; i < argc; ++i) {
4152 /* The encodings should all work, given that
4153 * we've checked all these args for the
4156 gchar *str = mono_utf8_from_external (argv [i]);
4157 MonoString *arg = mono_string_new (domain, str);
4158 mono_array_setref (args, i, arg);
4162 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, 0, &error);
4163 mono_error_assert_ok (&error);
4166 mono_assembly_set_main (method->klass->image->assembly);
4172 * mono_runtime_run_main:
4173 * @method: the method to start the application with (usually Main)
4174 * @argc: number of arguments from the command line
4175 * @argv: array of strings from the command line
4176 * @exc: excetption results
4178 * Execute a standard Main() method (argc/argv contains the
4179 * executable name). This method also sets the command line argument value
4180 * needed by System.Environment.
4185 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
4188 MONO_REQ_GC_UNSAFE_MODE;
4191 MonoArray *args = prepare_run_main (method, argc, argv);
4194 res = mono_runtime_try_exec_main (method, args, exc);
4196 res = mono_runtime_exec_main_checked (method, args, &error);
4197 mono_error_raise_exception (&error); /* OK to throw, external only without a better alternative */
4203 * mono_runtime_run_main_checked:
4204 * @method: the method to start the application with (usually Main)
4205 * @argc: number of arguments from the command line
4206 * @argv: array of strings from the command line
4207 * @error: set on error
4209 * Execute a standard Main() method (argc/argv contains the
4210 * executable name). This method also sets the command line argument value
4211 * needed by System.Environment. On failure sets @error.
4216 mono_runtime_run_main_checked (MonoMethod *method, int argc, char* argv[],
4219 mono_error_init (error);
4220 MonoArray *args = prepare_run_main (method, argc, argv);
4221 return mono_runtime_exec_main_checked (method, args, error);
4225 * mono_runtime_try_run_main:
4226 * @method: the method to start the application with (usually Main)
4227 * @argc: number of arguments from the command line
4228 * @argv: array of strings from the command line
4229 * @exc: set if Main throws an exception
4230 * @error: set if Main can't be executed
4232 * Execute a standard Main() method (argc/argv contains the executable
4233 * name). This method also sets the command line argument value needed
4234 * by System.Environment. On failure sets @error if Main can't be
4235 * executed or @exc if it threw and exception.
4240 mono_runtime_try_run_main (MonoMethod *method, int argc, char* argv[],
4244 MonoArray *args = prepare_run_main (method, argc, argv);
4245 return mono_runtime_try_exec_main (method, args, exc);
4250 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4252 static MonoMethod *serialize_method;
4258 if (!serialize_method) {
4259 MonoClass *klass = mono_class_get_remoting_services_class ();
4260 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
4263 if (!serialize_method) {
4268 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
4273 array = mono_runtime_try_invoke (serialize_method, NULL, params, exc, &error);
4274 if (*exc == NULL && !mono_error_ok (&error))
4275 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert serialize_object to MonoError */
4277 mono_error_cleanup (&error);
4286 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4288 MONO_REQ_GC_UNSAFE_MODE;
4290 static MonoMethod *deserialize_method;
4296 if (!deserialize_method) {
4297 MonoClass *klass = mono_class_get_remoting_services_class ();
4298 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
4300 if (!deserialize_method) {
4308 result = mono_runtime_try_invoke (deserialize_method, NULL, params, exc, &error);
4309 if (*exc == NULL && !mono_error_ok (&error))
4310 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert deserialize_object to MonoError */
4312 mono_error_cleanup (&error);
4320 #ifndef DISABLE_REMOTING
4322 make_transparent_proxy (MonoObject *obj, MonoError *error)
4324 MONO_REQ_GC_UNSAFE_MODE;
4326 static MonoMethod *get_proxy_method;
4328 MonoDomain *domain = mono_domain_get ();
4329 MonoRealProxy *real_proxy;
4330 MonoReflectionType *reflection_type;
4331 MonoTransparentProxy *transparent_proxy;
4333 mono_error_init (error);
4335 if (!get_proxy_method)
4336 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
4338 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
4340 real_proxy = (MonoRealProxy*) mono_object_new_checked (domain, mono_defaults.real_proxy_class, error);
4341 return_val_if_nok (error, NULL);
4342 reflection_type = mono_type_get_object_checked (domain, &obj->vtable->klass->byval_arg, error);
4343 return_val_if_nok (error, NULL);
4345 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
4346 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
4348 MonoObject *exc = NULL;
4350 transparent_proxy = (MonoTransparentProxy*) mono_runtime_try_invoke (get_proxy_method, real_proxy, NULL, &exc, error);
4351 if (exc != NULL && is_ok (error))
4352 mono_error_set_exception_instance (error, (MonoException*)exc);
4354 return (MonoObject*) transparent_proxy;
4356 #endif /* DISABLE_REMOTING */
4359 * mono_object_xdomain_representation
4361 * @target_domain: a domain
4362 * @error: set on error.
4364 * Creates a representation of obj in the domain target_domain. This
4365 * is either a copy of obj arrived through via serialization and
4366 * deserialization or a proxy, depending on whether the object is
4367 * serializable or marshal by ref. obj must not be in target_domain.
4369 * If the object cannot be represented in target_domain, NULL is
4370 * returned and @error is set appropriately.
4373 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoError *error)
4375 MONO_REQ_GC_UNSAFE_MODE;
4377 mono_error_init (error);
4378 MonoObject *deserialized = NULL;
4380 #ifndef DISABLE_REMOTING
4381 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
4382 deserialized = make_transparent_proxy (obj, error);
4387 gboolean failure = FALSE;
4388 MonoDomain *domain = mono_domain_get ();
4389 MonoObject *serialized;
4390 MonoObject *exc = NULL;
4392 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
4393 serialized = serialize_object (obj, &failure, &exc);
4394 mono_domain_set_internal_with_options (target_domain, FALSE);
4396 deserialized = deserialize_object (serialized, &failure, &exc);
4397 if (domain != target_domain)
4398 mono_domain_set_internal_with_options (domain, FALSE);
4400 mono_error_set_exception_instance (error, (MonoException*)exc);
4403 return deserialized;
4406 /* Used in call_unhandled_exception_delegate */
4408 create_unhandled_exception_eventargs (MonoObject *exc, MonoError *error)
4410 MONO_REQ_GC_UNSAFE_MODE;
4412 mono_error_init (error);
4415 MonoMethod *method = NULL;
4416 MonoBoolean is_terminating = TRUE;
4419 klass = mono_class_get_unhandled_exception_event_args_class ();
4420 mono_class_init (klass);
4422 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4423 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
4427 args [1] = &is_terminating;
4429 obj = mono_object_new_checked (mono_domain_get (), klass, error);
4430 return_val_if_nok (error, NULL);
4432 mono_runtime_invoke_checked (method, obj, args, error);
4433 return_val_if_nok (error, NULL);
4438 /* Used in mono_unhandled_exception */
4440 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4441 MONO_REQ_GC_UNSAFE_MODE;
4444 MonoObject *e = NULL;
4446 MonoDomain *current_domain = mono_domain_get ();
4448 if (domain != current_domain)
4449 mono_domain_set_internal_with_options (domain, FALSE);
4451 g_assert (domain == mono_object_domain (domain->domain));
4453 if (mono_object_domain (exc) != domain) {
4455 exc = mono_object_xdomain_representation (exc, domain, &error);
4457 if (!is_ok (&error)) {
4458 MonoError inner_error;
4459 MonoException *serialization_exc = mono_error_convert_to_exception (&error);
4460 exc = mono_object_xdomain_representation ((MonoObject*)serialization_exc, domain, &inner_error);
4461 mono_error_assert_ok (&inner_error);
4463 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4464 "System.Runtime.Serialization", "SerializationException",
4465 "Could not serialize unhandled exception.");
4469 g_assert (mono_object_domain (exc) == domain);
4471 pa [0] = domain->domain;
4472 pa [1] = create_unhandled_exception_eventargs (exc, &error);
4473 mono_error_assert_ok (&error);
4474 mono_runtime_delegate_try_invoke (delegate, pa, &e, &error);
4475 if (!is_ok (&error)) {
4477 e = (MonoObject*)mono_error_convert_to_exception (&error);
4479 mono_error_cleanup (&error);
4482 if (domain != current_domain)
4483 mono_domain_set_internal_with_options (current_domain, FALSE);
4486 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4487 if (!mono_error_ok (&error)) {
4488 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4489 mono_error_cleanup (&error);
4491 g_warning ("exception inside UnhandledException handler: %s\n", msg);
4497 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4500 * mono_runtime_unhandled_exception_policy_set:
4501 * @policy: the new policy
4503 * This is a VM internal routine.
4505 * Sets the runtime policy for handling unhandled exceptions.
4508 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4509 runtime_unhandled_exception_policy = policy;
4513 * mono_runtime_unhandled_exception_policy_get:
4515 * This is a VM internal routine.
4517 * Gets the runtime policy for handling unhandled exceptions.
4519 MonoRuntimeUnhandledExceptionPolicy
4520 mono_runtime_unhandled_exception_policy_get (void) {
4521 return runtime_unhandled_exception_policy;
4525 * mono_unhandled_exception:
4526 * @exc: exception thrown
4528 * This is a VM internal routine.
4530 * We call this function when we detect an unhandled exception
4531 * in the default domain.
4533 * It invokes the * UnhandledException event in AppDomain or prints
4534 * a warning to the console
4537 mono_unhandled_exception (MonoObject *exc)
4539 MONO_REQ_GC_UNSAFE_MODE;
4542 MonoClassField *field;
4543 MonoDomain *current_domain, *root_domain;
4544 MonoObject *current_appdomain_delegate = NULL, *root_appdomain_delegate = NULL;
4546 if (mono_class_has_parent (exc->vtable->klass, mono_defaults.threadabortexception_class))
4549 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4552 current_domain = mono_domain_get ();
4553 root_domain = mono_get_root_domain ();
4555 root_appdomain_delegate = mono_field_get_value_object_checked (root_domain, field, (MonoObject*) root_domain->domain, &error);
4556 mono_error_assert_ok (&error);
4557 if (current_domain != root_domain) {
4558 current_appdomain_delegate = mono_field_get_value_object_checked (current_domain, field, (MonoObject*) current_domain->domain, &error);
4559 mono_error_assert_ok (&error);
4562 if (!current_appdomain_delegate && !root_appdomain_delegate) {
4563 mono_print_unhandled_exception (exc);
4565 /* unhandled exception callbacks must not be aborted */
4566 mono_threads_begin_abort_protected_block ();
4567 if (root_appdomain_delegate)
4568 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4569 if (current_appdomain_delegate)
4570 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4571 mono_threads_end_abort_protected_block ();
4574 /* set exitcode only if we will abort the process */
4575 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4576 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4578 mono_environment_exitcode_set (1);
4583 * mono_runtime_exec_managed_code:
4584 * @domain: Application domain
4585 * @main_func: function to invoke from the execution thread
4586 * @main_args: parameter to the main_func
4588 * Launch a new thread to execute a function
4590 * main_func is called back from the thread with main_args as the
4591 * parameter. The callback function is expected to start Main()
4592 * eventually. This function then waits for all managed threads to
4594 * It is not necesseray anymore to execute managed code in a subthread,
4595 * so this function should not be used anymore by default: just
4596 * execute the code and then call mono_thread_manage ().
4599 mono_runtime_exec_managed_code (MonoDomain *domain,
4600 MonoMainThreadFunc main_func,
4604 mono_thread_create_checked (domain, main_func, main_args, &error);
4605 mono_error_assert_ok (&error);
4607 mono_thread_manage ();
4611 prepare_thread_to_exec_main (MonoDomain *domain, MonoMethod *method)
4613 MonoInternalThread* thread = mono_thread_internal_current ();
4614 MonoCustomAttrInfo* cinfo;
4615 gboolean has_stathread_attribute;
4617 if (!domain->entry_assembly) {
4619 MonoAssembly *assembly;
4621 assembly = method->klass->image->assembly;
4622 domain->entry_assembly = assembly;
4623 /* Domains created from another domain already have application_base and configuration_file set */
4624 if (domain->setup->application_base == NULL) {
4625 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4628 if (domain->setup->configuration_file == NULL) {
4629 str = g_strconcat (assembly->image->name, ".config", NULL);
4630 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4632 mono_domain_set_options_from_config (domain);
4636 MonoError cattr_error;
4637 cinfo = mono_custom_attrs_from_method_checked (method, &cattr_error);
4638 mono_error_cleanup (&cattr_error); /* FIXME warn here? */
4640 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, mono_class_get_sta_thread_attribute_class ());
4642 mono_custom_attrs_free (cinfo);
4644 has_stathread_attribute = FALSE;
4646 if (has_stathread_attribute) {
4647 thread->apartment_state = ThreadApartmentState_STA;
4649 thread->apartment_state = ThreadApartmentState_MTA;
4651 mono_thread_init_apartment_state ();
4656 do_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4658 MONO_REQ_GC_UNSAFE_MODE;
4663 mono_error_init (error);
4668 /* FIXME: check signature of method */
4669 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4671 res = mono_runtime_invoke_checked (method, NULL, pa, error);
4673 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4676 mono_environment_exitcode_set (rval);
4678 mono_runtime_invoke_checked (method, NULL, pa, error);
4690 do_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4692 MONO_REQ_GC_UNSAFE_MODE;
4702 /* FIXME: check signature of method */
4703 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4704 MonoError inner_error;
4706 res = mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4707 if (*exc == NULL && !mono_error_ok (&inner_error))
4708 *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4710 mono_error_cleanup (&inner_error);
4713 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4717 mono_environment_exitcode_set (rval);
4719 MonoError inner_error;
4720 mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4721 if (*exc == NULL && !mono_error_ok (&inner_error))
4722 *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4724 mono_error_cleanup (&inner_error);
4729 /* If the return type of Main is void, only
4730 * set the exitcode if an exception was thrown
4731 * (we don't want to blow away an
4732 * explicitly-set exit code)
4735 mono_environment_exitcode_set (rval);
4743 * Execute a standard Main() method (args doesn't contain the
4747 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4750 prepare_thread_to_exec_main (mono_object_domain (args), method);
4752 int rval = do_try_exec_main (method, args, exc);
4755 int rval = do_exec_main_checked (method, args, &error);
4756 mono_error_raise_exception (&error); /* OK to throw, external only with no better option */
4762 * Execute a standard Main() method (args doesn't contain the
4765 * On failure sets @error
4768 mono_runtime_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4770 mono_error_init (error);
4771 prepare_thread_to_exec_main (mono_object_domain (args), method);
4772 return do_exec_main_checked (method, args, error);
4776 * Execute a standard Main() method (args doesn't contain the
4779 * On failure sets @error if Main couldn't be executed, or @exc if it threw an exception.
4782 mono_runtime_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4784 prepare_thread_to_exec_main (mono_object_domain (args), method);
4785 return do_try_exec_main (method, args, exc);
4790 /** invoke_array_extract_argument:
4791 * @params: array of arguments to the method.
4792 * @i: the index of the argument to extract.
4793 * @t: ith type from the method signature.
4794 * @has_byref_nullables: outarg - TRUE if method expects a byref nullable argument
4795 * @error: set on error.
4797 * Given an array of method arguments, return the ith one using the corresponding type
4798 * to perform necessary unboxing. If method expects a ref nullable argument, writes TRUE to @has_byref_nullables.
4800 * On failure sets @error and returns NULL.
4803 invoke_array_extract_argument (MonoArray *params, int i, MonoType *t, gboolean* has_byref_nullables, MonoError *error)
4805 MonoType *t_orig = t;
4806 gpointer result = NULL;
4807 mono_error_init (error);
4812 case MONO_TYPE_BOOLEAN:
4815 case MONO_TYPE_CHAR:
4824 case MONO_TYPE_VALUETYPE:
4825 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (t_orig))) {
4826 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4827 result = mono_array_get (params, MonoObject*, i);
4829 *has_byref_nullables = TRUE;
4831 /* MS seems to create the objects if a null is passed in */
4832 if (!mono_array_get (params, MonoObject*, i)) {
4833 MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (t_orig), error);
4834 return_val_if_nok (error, NULL);
4835 mono_array_setref (params, i, o);
4840 * We can't pass the unboxed vtype byref to the callee, since
4841 * that would mean the callee would be able to modify boxed
4842 * primitive types. So we (and MS) make a copy of the boxed
4843 * object, pass that to the callee, and replace the original
4844 * boxed object in the arg array with the copy.
4846 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4847 MonoObject *copy = mono_value_box_checked (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig), error);
4848 return_val_if_nok (error, NULL);
4849 mono_array_setref (params, i, copy);
4852 result = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4855 case MONO_TYPE_STRING:
4856 case MONO_TYPE_OBJECT:
4857 case MONO_TYPE_CLASS:
4858 case MONO_TYPE_ARRAY:
4859 case MONO_TYPE_SZARRAY:
4861 result = mono_array_addr (params, MonoObject*, i);
4862 // FIXME: I need to check this code path
4864 result = mono_array_get (params, MonoObject*, i);
4866 case MONO_TYPE_GENERICINST:
4868 t = &t->data.generic_class->container_class->this_arg;
4870 t = &t->data.generic_class->container_class->byval_arg;
4872 case MONO_TYPE_PTR: {
4875 /* The argument should be an IntPtr */
4876 arg = mono_array_get (params, MonoObject*, i);
4880 g_assert (arg->vtable->klass == mono_defaults.int_class);
4881 result = ((MonoIntPtr*)arg)->m_value;
4886 g_error ("type 0x%x not handled in mono_runtime_invoke_array", t_orig->type);
4891 * mono_runtime_invoke_array:
4892 * @method: method to invoke
4893 * @obJ: object instance
4894 * @params: arguments to the method
4895 * @exc: exception information.
4897 * Invokes the method represented by @method on the object @obj.
4899 * obj is the 'this' pointer, it should be NULL for static
4900 * methods, a MonoObject* for object instances and a pointer to
4901 * the value type for value types.
4903 * The params array contains the arguments to the method with the
4904 * same convention: MonoObject* pointers for object instances and
4905 * pointers to the value type otherwise. The _invoke_array
4906 * variant takes a C# object[] as the params argument (MonoArray
4907 * *params): in this case the value types are boxed inside the
4908 * respective reference representation.
4910 * From unmanaged code you'll usually use the
4911 * mono_runtime_invoke_checked() variant.
4913 * Note that this function doesn't handle virtual methods for
4914 * you, it will exec the exact method you pass: we still need to
4915 * expose a function to lookup the derived class implementation
4916 * of a virtual method (there are examples of this in the code,
4919 * You can pass NULL as the exc argument if you don't want to
4920 * catch exceptions, otherwise, *exc will be set to the exception
4921 * thrown, if any. if an exception is thrown, you can't use the
4922 * MonoObject* result from the function.
4924 * If the method returns a value type, it is boxed in an object
4928 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4933 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, exc, &error);
4935 mono_error_cleanup (&error);
4938 if (!is_ok (&error))
4939 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
4943 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, NULL, &error);
4944 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
4950 * mono_runtime_invoke_array_checked:
4951 * @method: method to invoke
4952 * @obJ: object instance
4953 * @params: arguments to the method
4954 * @error: set on failure.
4956 * Invokes the method represented by @method on the object @obj.
4958 * obj is the 'this' pointer, it should be NULL for static
4959 * methods, a MonoObject* for object instances and a pointer to
4960 * the value type for value types.
4962 * The params array contains the arguments to the method with the
4963 * same convention: MonoObject* pointers for object instances and
4964 * pointers to the value type otherwise. The _invoke_array
4965 * variant takes a C# object[] as the params argument (MonoArray
4966 * *params): in this case the value types are boxed inside the
4967 * respective reference representation.
4969 * From unmanaged code you'll usually use the
4970 * mono_runtime_invoke_checked() variant.
4972 * Note that this function doesn't handle virtual methods for
4973 * you, it will exec the exact method you pass: we still need to
4974 * expose a function to lookup the derived class implementation
4975 * of a virtual method (there are examples of this in the code,
4978 * On failure or exception, @error will be set. In that case, you
4979 * can't use the MonoObject* result from the function.
4981 * If the method returns a value type, it is boxed in an object
4985 mono_runtime_invoke_array_checked (MonoMethod *method, void *obj, MonoArray *params,
4988 mono_error_init (error);
4989 return mono_runtime_try_invoke_array (method, obj, params, NULL, error);
4993 * mono_runtime_try_invoke_array:
4994 * @method: method to invoke
4995 * @obJ: object instance
4996 * @params: arguments to the method
4997 * @exc: exception information.
4998 * @error: set on failure.
5000 * Invokes the method represented by @method on the object @obj.
5002 * obj is the 'this' pointer, it should be NULL for static
5003 * methods, a MonoObject* for object instances and a pointer to
5004 * the value type for value types.
5006 * The params array contains the arguments to the method with the
5007 * same convention: MonoObject* pointers for object instances and
5008 * pointers to the value type otherwise. The _invoke_array
5009 * variant takes a C# object[] as the params argument (MonoArray
5010 * *params): in this case the value types are boxed inside the
5011 * respective reference representation.
5013 * From unmanaged code you'll usually use the
5014 * mono_runtime_invoke_checked() variant.
5016 * Note that this function doesn't handle virtual methods for
5017 * you, it will exec the exact method you pass: we still need to
5018 * expose a function to lookup the derived class implementation
5019 * of a virtual method (there are examples of this in the code,
5022 * You can pass NULL as the exc argument if you don't want to catch
5023 * exceptions, otherwise, *exc will be set to the exception thrown, if
5024 * any. On other failures, @error will be set. If an exception is
5025 * thrown or there's an error, you can't use the MonoObject* result
5026 * from the function.
5028 * If the method returns a value type, it is boxed in an object
5032 mono_runtime_try_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
5033 MonoObject **exc, MonoError *error)
5035 MONO_REQ_GC_UNSAFE_MODE;
5037 mono_error_init (error);
5039 MonoMethodSignature *sig = mono_method_signature (method);
5040 gpointer *pa = NULL;
5043 gboolean has_byref_nullables = FALSE;
5045 if (NULL != params) {
5046 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
5047 for (i = 0; i < mono_array_length (params); i++) {
5048 MonoType *t = sig->params [i];
5049 pa [i] = invoke_array_extract_argument (params, i, t, &has_byref_nullables, error);
5050 return_val_if_nok (error, NULL);
5054 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
5057 if (mono_class_is_nullable (method->klass)) {
5058 /* Need to create a boxed vtype instead */
5064 return mono_value_box_checked (mono_domain_get (), method->klass->cast_class, pa [0], error);
5069 obj = mono_object_new_checked (mono_domain_get (), method->klass, error);
5070 mono_error_assert_ok (error);
5071 g_assert (obj); /*maybe we should raise a TLE instead?*/
5072 #ifndef DISABLE_REMOTING
5073 if (mono_object_is_transparent_proxy (obj)) {
5074 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
5077 if (method->klass->valuetype)
5078 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
5081 } else if (method->klass->valuetype) {
5082 obj = mono_value_box_checked (mono_domain_get (), method->klass, obj, error);
5083 return_val_if_nok (error, NULL);
5087 mono_runtime_try_invoke (method, o, pa, exc, error);
5089 mono_runtime_invoke_checked (method, o, pa, error);
5092 return (MonoObject *)obj;
5094 if (mono_class_is_nullable (method->klass)) {
5095 MonoObject *nullable;
5097 /* Convert the unboxed vtype into a Nullable structure */
5098 nullable = mono_object_new_checked (mono_domain_get (), method->klass, error);
5099 return_val_if_nok (error, NULL);
5101 MonoObject *boxed = mono_value_box_checked (mono_domain_get (), method->klass->cast_class, obj, error);
5102 return_val_if_nok (error, NULL);
5103 mono_nullable_init ((guint8 *)mono_object_unbox (nullable), boxed, method->klass);
5104 obj = mono_object_unbox (nullable);
5107 /* obj must be already unboxed if needed */
5109 res = mono_runtime_try_invoke (method, obj, pa, exc, error);
5111 res = mono_runtime_invoke_checked (method, obj, pa, error);
5113 return_val_if_nok (error, NULL);
5115 if (sig->ret->type == MONO_TYPE_PTR) {
5116 MonoClass *pointer_class;
5117 static MonoMethod *box_method;
5119 MonoObject *box_exc;
5122 * The runtime-invoke wrapper returns a boxed IntPtr, need to
5123 * convert it to a Pointer object.
5125 pointer_class = mono_class_get_pointer_class ();
5127 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
5129 g_assert (res->vtable->klass == mono_defaults.int_class);
5130 box_args [0] = ((MonoIntPtr*)res)->m_value;
5131 box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, error);
5132 return_val_if_nok (error, NULL);
5134 res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, error);
5135 g_assert (box_exc == NULL);
5136 mono_error_assert_ok (error);
5139 if (has_byref_nullables) {
5141 * The runtime invoke wrapper already converted byref nullables back,
5142 * and stored them in pa, we just need to copy them back to the
5145 for (i = 0; i < mono_array_length (params); i++) {
5146 MonoType *t = sig->params [i];
5148 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
5149 mono_array_setref (params, i, pa [i]);
5159 * @klass: the class of the object that we want to create
5161 * Returns: a newly created object whose definition is
5162 * looked up using @klass. This will not invoke any constructors,
5163 * so the consumer of this routine has to invoke any constructors on
5164 * its own to initialize the object.
5166 * It returns NULL on failure.
5169 mono_object_new (MonoDomain *domain, MonoClass *klass)
5171 MONO_REQ_GC_UNSAFE_MODE;
5175 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5177 mono_error_cleanup (&error);
5182 ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
5184 MONO_REQ_GC_UNSAFE_MODE;
5188 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5190 mono_error_set_pending_exception (&error);
5195 * mono_object_new_checked:
5196 * @klass: the class of the object that we want to create
5197 * @error: set on error
5199 * Returns: a newly created object whose definition is
5200 * looked up using @klass. This will not invoke any constructors,
5201 * so the consumer of this routine has to invoke any constructors on
5202 * its own to initialize the object.
5204 * It returns NULL on failure and sets @error.
5207 mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
5209 MONO_REQ_GC_UNSAFE_MODE;
5213 vtable = mono_class_vtable (domain, klass);
5214 g_assert (vtable); /* FIXME don't swallow the error */
5216 MonoObject *o = mono_object_new_specific_checked (vtable, error);
5221 * mono_object_new_pinned:
5223 * Same as mono_object_new, but the returned object will be pinned.
5224 * For SGEN, these objects will only be freed at appdomain unload.
5227 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
5229 MONO_REQ_GC_UNSAFE_MODE;
5233 mono_error_init (error);
5235 vtable = mono_class_vtable (domain, klass);
5236 g_assert (vtable); /* FIXME don't swallow the error */
5238 MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
5240 if (G_UNLIKELY (!o))
5241 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
5242 else if (G_UNLIKELY (vtable->klass->has_finalize))
5243 mono_object_register_finalizer (o);
5249 * mono_object_new_specific:
5250 * @vtable: the vtable of the object that we want to create
5252 * Returns: A newly created object with class and domain specified
5256 mono_object_new_specific (MonoVTable *vtable)
5259 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5260 mono_error_cleanup (&error);
5266 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
5268 MONO_REQ_GC_UNSAFE_MODE;
5272 mono_error_init (error);
5274 /* check for is_com_object for COM Interop */
5275 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
5278 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
5281 MonoClass *klass = mono_class_get_activation_services_class ();
5284 mono_class_init (klass);
5286 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
5288 mono_error_set_not_supported (error, "Linked away.");
5291 vtable->domain->create_proxy_for_type_method = im;
5294 pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
5295 if (!mono_error_ok (error))
5298 o = mono_runtime_invoke_checked (im, NULL, pa, error);
5299 if (!mono_error_ok (error))
5306 return mono_object_new_alloc_specific_checked (vtable, error);
5310 ves_icall_object_new_specific (MonoVTable *vtable)
5313 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5314 mono_error_set_pending_exception (&error);
5320 * mono_object_new_alloc_specific:
5321 * @vtable: virtual table for the object.
5323 * This function allocates a new `MonoObject` with the type derived
5324 * from the @vtable information. If the class of this object has a
5325 * finalizer, then the object will be tracked for finalization.
5327 * This method might raise an exception on errors. Use the
5328 * `mono_object_new_fast_checked` method if you want to manually raise
5331 * Returns: the allocated object.
5334 mono_object_new_alloc_specific (MonoVTable *vtable)
5337 MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
5338 mono_error_cleanup (&error);
5344 * mono_object_new_alloc_specific_checked:
5345 * @vtable: virtual table for the object.
5346 * @error: holds the error return value.
5348 * This function allocates a new `MonoObject` with the type derived
5349 * from the @vtable information. If the class of this object has a
5350 * finalizer, then the object will be tracked for finalization.
5352 * If there is not enough memory, the @error parameter will be set
5353 * and will contain a user-visible message with the amount of bytes
5354 * that were requested.
5356 * Returns: the allocated object, or NULL if there is not enough memory
5360 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
5362 MONO_REQ_GC_UNSAFE_MODE;
5366 mono_error_init (error);
5368 o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5370 if (G_UNLIKELY (!o))
5371 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5372 else if (G_UNLIKELY (vtable->klass->has_finalize))
5373 mono_object_register_finalizer (o);
5379 * mono_object_new_fast:
5380 * @vtable: virtual table for the object.
5382 * This function allocates a new `MonoObject` with the type derived
5383 * from the @vtable information. The returned object is not tracked
5384 * for finalization. If your object implements a finalizer, you should
5385 * use `mono_object_new_alloc_specific` instead.
5387 * This method might raise an exception on errors. Use the
5388 * `mono_object_new_fast_checked` method if you want to manually raise
5391 * Returns: the allocated object.
5394 mono_object_new_fast (MonoVTable *vtable)
5397 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5398 mono_error_cleanup (&error);
5404 * mono_object_new_fast_checked:
5405 * @vtable: virtual table for the object.
5406 * @error: holds the error return value.
5408 * This function allocates a new `MonoObject` with the type derived
5409 * from the @vtable information. The returned object is not tracked
5410 * for finalization. If your object implements a finalizer, you should
5411 * use `mono_object_new_alloc_specific_checked` instead.
5413 * If there is not enough memory, the @error parameter will be set
5414 * and will contain a user-visible message with the amount of bytes
5415 * that were requested.
5417 * Returns: the allocated object, or NULL if there is not enough memory
5421 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
5423 MONO_REQ_GC_UNSAFE_MODE;
5427 mono_error_init (error);
5429 o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5431 if (G_UNLIKELY (!o))
5432 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5438 ves_icall_object_new_fast (MonoVTable *vtable)
5441 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5442 mono_error_set_pending_exception (&error);
5448 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
5450 MONO_REQ_GC_UNSAFE_MODE;
5454 mono_error_init (error);
5456 o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
5458 if (G_UNLIKELY (!o))
5459 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5460 else if (G_UNLIKELY (vtable->klass->has_finalize))
5461 mono_object_register_finalizer (o);
5467 * mono_class_get_allocation_ftn:
5469 * @for_box: the object will be used for boxing
5470 * @pass_size_in_words:
5472 * Return the allocation function appropriate for the given class.
5476 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
5478 MONO_REQ_GC_NEUTRAL_MODE;
5480 *pass_size_in_words = FALSE;
5482 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass))
5483 return ves_icall_object_new_specific;
5485 if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
5487 return ves_icall_object_new_fast;
5490 * FIXME: This is actually slower than ves_icall_object_new_fast, because
5491 * of the overhead of parameter passing.
5494 *pass_size_in_words = TRUE;
5495 #ifdef GC_REDIRECT_TO_LOCAL
5496 return GC_local_gcj_fast_malloc;
5498 return GC_gcj_fast_malloc;
5503 return ves_icall_object_new_specific;
5507 * mono_object_new_from_token:
5508 * @image: Context where the type_token is hosted
5509 * @token: a token of the type that we want to create
5511 * Returns: A newly created object whose definition is
5512 * looked up using @token in the @image image
5515 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
5517 MONO_REQ_GC_UNSAFE_MODE;
5523 klass = mono_class_get_checked (image, token, &error);
5524 mono_error_assert_ok (&error);
5526 result = mono_object_new_checked (domain, klass, &error);
5528 mono_error_cleanup (&error);
5535 * mono_object_clone:
5536 * @obj: the object to clone
5538 * Returns: A newly created object who is a shallow copy of @obj
5541 mono_object_clone (MonoObject *obj)
5544 MonoObject *o = mono_object_clone_checked (obj, &error);
5545 mono_error_cleanup (&error);
5551 mono_object_clone_checked (MonoObject *obj, MonoError *error)
5553 MONO_REQ_GC_UNSAFE_MODE;
5558 mono_error_init (error);
5560 size = obj->vtable->klass->instance_size;
5562 if (obj->vtable->klass->rank)
5563 return (MonoObject*)mono_array_clone_checked ((MonoArray*)obj, error);
5565 o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
5567 if (G_UNLIKELY (!o)) {
5568 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5572 /* If the object doesn't contain references this will do a simple memmove. */
5573 mono_gc_wbarrier_object_copy (o, obj);
5575 if (obj->vtable->klass->has_finalize)
5576 mono_object_register_finalizer (o);
5581 * mono_array_full_copy:
5582 * @src: source array to copy
5583 * @dest: destination array
5585 * Copies the content of one array to another with exactly the same type and size.
5588 mono_array_full_copy (MonoArray *src, MonoArray *dest)
5590 MONO_REQ_GC_UNSAFE_MODE;
5593 MonoClass *klass = src->obj.vtable->klass;
5595 g_assert (klass == dest->obj.vtable->klass);
5597 size = mono_array_length (src);
5598 g_assert (size == mono_array_length (dest));
5599 size *= mono_array_element_size (klass);
5601 array_full_copy_unchecked_size (src, dest, klass, size);
5605 array_full_copy_unchecked_size (MonoArray *src, MonoArray *dest, MonoClass *klass, uintptr_t size)
5608 if (klass->element_class->valuetype) {
5609 if (klass->element_class->has_references)
5610 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
5612 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5614 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
5617 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5622 * mono_array_clone_in_domain:
5623 * @domain: the domain in which the array will be cloned into
5624 * @array: the array to clone
5625 * @error: set on error
5627 * This routine returns a copy of the array that is hosted on the
5628 * specified MonoDomain. On failure returns NULL and sets @error.
5631 mono_array_clone_in_domain (MonoDomain *domain, MonoArrayHandle array_handle, MonoError *error)
5633 MONO_REQ_GC_UNSAFE_MODE;
5635 MonoArrayHandle result = MONO_HANDLE_NEW (MonoArray, NULL);
5637 MonoClass *klass = mono_handle_class (array_handle);
5639 mono_error_init (error);
5641 /* Pin source array here - if bounds is non-NULL, it's a pointer into the object data */
5642 uint32_t src_handle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, array_handle), TRUE);
5644 MonoArrayBounds *array_bounds = MONO_HANDLE_GETVAL (array_handle, bounds);
5646 if (array_bounds == NULL) {
5647 size = mono_array_handle_length (array_handle);
5648 o = mono_array_new_full_handle (domain, klass, &size, NULL, error);
5651 size *= mono_array_element_size (klass);
5653 uintptr_t *sizes = (uintptr_t *)alloca (klass->rank * sizeof (uintptr_t));
5654 intptr_t *lower_bounds = (intptr_t *)alloca (klass->rank * sizeof (intptr_t));
5655 size = mono_array_element_size (klass);
5656 for (int i = 0; i < klass->rank; ++i) {
5657 sizes [i] = array_bounds [i].length;
5658 size *= array_bounds [i].length;
5659 lower_bounds [i] = array_bounds [i].lower_bound;
5661 o = mono_array_new_full_handle (domain, klass, sizes, lower_bounds, error);
5666 uint32_t dst_handle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, o), TRUE);
5667 array_full_copy_unchecked_size (MONO_HANDLE_RAW (array_handle), MONO_HANDLE_RAW (o), klass, size);
5668 mono_gchandle_free (dst_handle);
5670 MONO_HANDLE_ASSIGN (result, o);
5673 mono_gchandle_free (src_handle);
5679 * @array: the array to clone
5681 * Returns: A newly created array who is a shallow copy of @array
5684 mono_array_clone (MonoArray *array)
5686 MONO_REQ_GC_UNSAFE_MODE;
5689 MonoArray *result = mono_array_clone_checked (array, &error);
5690 mono_error_cleanup (&error);
5695 * mono_array_clone_checked:
5696 * @array: the array to clone
5697 * @error: set on error
5699 * Returns: A newly created array who is a shallow copy of @array. On
5700 * failure returns NULL and sets @error.
5703 mono_array_clone_checked (MonoArray *array_raw, MonoError *error)
5705 MONO_REQ_GC_UNSAFE_MODE;
5706 HANDLE_FUNCTION_ENTER ();
5707 /* FIXME: callers of mono_array_clone_checked should use handles */
5708 mono_error_init (error);
5709 MONO_HANDLE_DCL (MonoArray, array);
5710 MonoArrayHandle result = mono_array_clone_in_domain (MONO_HANDLE_DOMAIN (array), array, error);
5711 HANDLE_FUNCTION_RETURN_OBJ (result);
5714 /* helper macros to check for overflow when calculating the size of arrays */
5715 #ifdef MONO_BIG_ARRAYS
5716 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
5717 #define MYGUINT_MAX MYGUINT64_MAX
5718 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5719 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
5720 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5721 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
5722 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
5724 #define MYGUINT32_MAX 4294967295U
5725 #define MYGUINT_MAX MYGUINT32_MAX
5726 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5727 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
5728 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5729 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
5730 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
5734 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
5736 MONO_REQ_GC_NEUTRAL_MODE;
5740 byte_len = mono_array_element_size (klass);
5741 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
5744 if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
5746 byte_len += MONO_SIZEOF_MONO_ARRAY;
5754 * mono_array_new_full:
5755 * @domain: domain where the object is created
5756 * @array_class: array class
5757 * @lengths: lengths for each dimension in the array
5758 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
5760 * This routine creates a new array objects with the given dimensions,
5761 * lower bounds and type.
5764 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
5767 MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
5768 mono_error_cleanup (&error);
5774 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
5776 MONO_REQ_GC_UNSAFE_MODE;
5778 uintptr_t byte_len = 0, len, bounds_size;
5781 MonoArrayBounds *bounds;
5785 mono_error_init (error);
5787 if (!array_class->inited)
5788 mono_class_init (array_class);
5792 /* A single dimensional array with a 0 lower bound is the same as an szarray */
5793 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
5795 if (len > MONO_ARRAY_MAX_INDEX) {
5796 mono_error_set_generic_error (error, "System", "OverflowException", "");
5801 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
5803 for (i = 0; i < array_class->rank; ++i) {
5804 if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
5805 mono_error_set_generic_error (error, "System", "OverflowException", "");
5808 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5809 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5816 if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5817 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5823 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5824 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5827 byte_len = (byte_len + 3) & ~3;
5828 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5829 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5832 byte_len += bounds_size;
5835 * Following three lines almost taken from mono_object_new ():
5836 * they need to be kept in sync.
5838 vtable = mono_class_vtable_full (domain, array_class, error);
5839 return_val_if_nok (error, NULL);
5842 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5844 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5846 if (G_UNLIKELY (!o)) {
5847 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5851 array = (MonoArray*)o;
5853 bounds = array->bounds;
5856 for (i = 0; i < array_class->rank; ++i) {
5857 bounds [i].length = lengths [i];
5859 bounds [i].lower_bound = lower_bounds [i];
5868 * @domain: domain where the object is created
5869 * @eclass: element class
5870 * @n: number of array elements
5872 * This routine creates a new szarray with @n elements of type @eclass.
5875 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5877 MONO_REQ_GC_UNSAFE_MODE;
5880 MonoArray *result = mono_array_new_checked (domain, eclass, n, &error);
5881 mono_error_cleanup (&error);
5886 * mono_array_new_checked:
5887 * @domain: domain where the object is created
5888 * @eclass: element class
5889 * @n: number of array elements
5890 * @error: set on error
5892 * This routine creates a new szarray with @n elements of type @eclass.
5893 * On failure returns NULL and sets @error.
5896 mono_array_new_checked (MonoDomain *domain, MonoClass *eclass, uintptr_t n, MonoError *error)
5900 mono_error_init (error);
5902 ac = mono_array_class_get (eclass, 1);
5905 MonoVTable *vtable = mono_class_vtable_full (domain, ac, error);
5906 return_val_if_nok (error, NULL);
5908 return mono_array_new_specific_checked (vtable, n, error);
5912 ves_icall_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5915 MonoArray *arr = mono_array_new_checked (domain, eclass, n, &error);
5916 mono_error_set_pending_exception (&error);
5922 * mono_array_new_specific:
5923 * @vtable: a vtable in the appropriate domain for an initialized class
5924 * @n: number of array elements
5926 * This routine is a fast alternative to mono_array_new() for code which
5927 * can be sure about the domain it operates in.
5930 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5933 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5934 mono_error_cleanup (&error);
5940 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
5942 MONO_REQ_GC_UNSAFE_MODE;
5947 mono_error_init (error);
5949 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
5950 mono_error_set_generic_error (error, "System", "OverflowException", "");
5954 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
5955 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5958 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
5960 if (G_UNLIKELY (!o)) {
5961 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5965 return (MonoArray*)o;
5969 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
5972 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5973 mono_error_set_pending_exception (&error);
5979 * mono_string_empty_wrapper:
5981 * Returns: The same empty string instance as the managed string.Empty
5984 mono_string_empty_wrapper (void)
5986 MonoDomain *domain = mono_domain_get ();
5987 return mono_string_empty (domain);
5991 * mono_string_empty:
5993 * Returns: The same empty string instance as the managed string.Empty
5996 mono_string_empty (MonoDomain *domain)
5999 g_assert (domain->empty_string);
6000 return domain->empty_string;
6004 * mono_string_new_utf16:
6005 * @text: a pointer to an utf16 string
6006 * @len: the length of the string
6008 * Returns: A newly created string object which contains @text.
6011 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
6013 MONO_REQ_GC_UNSAFE_MODE;
6016 MonoString *res = NULL;
6017 res = mono_string_new_utf16_checked (domain, text, len, &error);
6018 mono_error_cleanup (&error);
6024 * mono_string_new_utf16_checked:
6025 * @text: a pointer to an utf16 string
6026 * @len: the length of the string
6027 * @error: written on error.
6029 * Returns: A newly created string object which contains @text.
6030 * On error, returns NULL and sets @error.
6033 mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
6035 MONO_REQ_GC_UNSAFE_MODE;
6039 mono_error_init (error);
6041 s = mono_string_new_size_checked (domain, len, error);
6043 memcpy (mono_string_chars (s), text, len * 2);
6049 * mono_string_new_utf16_handle:
6050 * @text: a pointer to an utf16 string
6051 * @len: the length of the string
6052 * @error: written on error.
6054 * Returns: A newly created string object which contains @text.
6055 * On error, returns NULL and sets @error.
6058 mono_string_new_utf16_handle (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
6060 return MONO_HANDLE_NEW (MonoString, mono_string_new_utf16_checked (domain, text, len, error));
6064 * mono_string_new_utf32:
6065 * @text: a pointer to an utf32 string
6066 * @len: the length of the string
6067 * @error: set on failure.
6069 * Returns: A newly created string object which contains @text. On failure returns NULL and sets @error.
6072 mono_string_new_utf32_checked (MonoDomain *domain, const mono_unichar4 *text, gint32 len, MonoError *error)
6074 MONO_REQ_GC_UNSAFE_MODE;
6077 mono_unichar2 *utf16_output = NULL;
6078 gint32 utf16_len = 0;
6079 GError *gerror = NULL;
6080 glong items_written;
6082 mono_error_init (error);
6083 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
6086 g_error_free (gerror);
6088 while (utf16_output [utf16_len]) utf16_len++;
6090 s = mono_string_new_size_checked (domain, utf16_len, error);
6091 return_val_if_nok (error, NULL);
6093 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
6095 g_free (utf16_output);
6101 * mono_string_new_utf32:
6102 * @text: a pointer to an utf32 string
6103 * @len: the length of the string
6105 * Returns: A newly created string object which contains @text.
6108 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
6111 MonoString *result = mono_string_new_utf32_checked (domain, text, len, &error);
6112 mono_error_cleanup (&error);
6117 * mono_string_new_size:
6118 * @text: a pointer to an utf16 string
6119 * @len: the length of the string
6121 * Returns: A newly created string object of @len
6124 mono_string_new_size (MonoDomain *domain, gint32 len)
6127 MonoString *str = mono_string_new_size_checked (domain, len, &error);
6128 mono_error_cleanup (&error);
6134 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
6136 MONO_REQ_GC_UNSAFE_MODE;
6142 mono_error_init (error);
6144 /* check for overflow */
6145 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
6146 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
6150 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
6151 g_assert (size > 0);
6153 vtable = mono_class_vtable (domain, mono_defaults.string_class);
6156 s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
6158 if (G_UNLIKELY (!s)) {
6159 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", size);
6167 * mono_string_new_len:
6168 * @text: a pointer to an utf8 string
6169 * @length: number of bytes in @text to consider
6171 * Returns: A newly created string object which contains @text.
6174 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
6176 MONO_REQ_GC_UNSAFE_MODE;
6179 MonoString *result = mono_string_new_len_checked (domain, text, length, &error);
6180 mono_error_cleanup (&error);
6185 * mono_string_new_len_checked:
6186 * @text: a pointer to an utf8 string
6187 * @length: number of bytes in @text to consider
6188 * @error: set on error
6190 * Returns: A newly created string object which contains @text. On
6191 * failure returns NULL and sets @error.
6194 mono_string_new_len_checked (MonoDomain *domain, const char *text, guint length, MonoError *error)
6196 MONO_REQ_GC_UNSAFE_MODE;
6198 mono_error_init (error);
6200 GError *eg_error = NULL;
6201 MonoString *o = NULL;
6203 glong items_written;
6205 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
6208 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6210 g_error_free (eg_error);
6219 * @text: a pointer to an utf8 string
6221 * Returns: A newly created string object which contains @text.
6223 * This function asserts if it cannot allocate a new string.
6225 * @deprecated Use mono_string_new_checked in new code.
6228 mono_string_new (MonoDomain *domain, const char *text)
6231 MonoString *res = NULL;
6232 res = mono_string_new_checked (domain, text, &error);
6233 mono_error_assert_ok (&error);
6238 * mono_string_new_checked:
6239 * @text: a pointer to an utf8 string
6240 * @merror: set on error
6242 * Returns: A newly created string object which contains @text.
6243 * On error returns NULL and sets @merror.
6246 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
6248 MONO_REQ_GC_UNSAFE_MODE;
6250 GError *eg_error = NULL;
6251 MonoString *o = NULL;
6253 glong items_written;
6256 mono_error_init (error);
6260 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &eg_error);
6263 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6265 g_error_free (eg_error);
6269 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
6274 MonoString *o = NULL;
6276 if (!g_utf8_validate (text, -1, &end)) {
6277 mono_error_set_argument (error, "text", "Not a valid utf8 string");
6281 len = g_utf8_strlen (text, -1);
6282 o = mono_string_new_size_checked (domain, len, error);
6285 str = mono_string_chars (o);
6287 while (text < end) {
6288 *str++ = g_utf8_get_char (text);
6289 text = g_utf8_next_char (text);
6298 * mono_string_new_wrapper:
6299 * @text: pointer to utf8 characters.
6301 * Helper function to create a string object from @text in the current domain.
6304 mono_string_new_wrapper (const char *text)
6306 MONO_REQ_GC_UNSAFE_MODE;
6308 MonoDomain *domain = mono_domain_get ();
6311 return mono_string_new (domain, text);
6318 * @class: the class of the value
6319 * @value: a pointer to the unboxed data
6321 * Returns: A newly created object which contains @value.
6324 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
6327 MonoObject *result = mono_value_box_checked (domain, klass, value, &error);
6328 mono_error_cleanup (&error);
6333 * mono_value_box_checked:
6334 * @domain: the domain of the new object
6335 * @class: the class of the value
6336 * @value: a pointer to the unboxed data
6337 * @error: set on error
6339 * Returns: A newly created object which contains @value. On failure
6340 * returns NULL and sets @error.
6343 mono_value_box_checked (MonoDomain *domain, MonoClass *klass, gpointer value, MonoError *error)
6345 MONO_REQ_GC_UNSAFE_MODE;
6350 mono_error_init (error);
6352 g_assert (klass->valuetype);
6353 if (mono_class_is_nullable (klass))
6354 return mono_nullable_box ((guint8 *)value, klass, error);
6356 vtable = mono_class_vtable (domain, klass);
6359 size = mono_class_instance_size (klass);
6360 res = mono_object_new_alloc_specific_checked (vtable, error);
6361 return_val_if_nok (error, NULL);
6363 size = size - sizeof (MonoObject);
6366 g_assert (size == mono_class_value_size (klass, NULL));
6367 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
6369 #if NO_UNALIGNED_ACCESS
6370 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6374 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
6377 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
6380 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
6383 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
6386 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6390 if (klass->has_finalize) {
6391 mono_object_register_finalizer (res);
6392 return_val_if_nok (error, NULL);
6399 * @dest: destination pointer
6400 * @src: source pointer
6401 * @klass: a valuetype class
6403 * Copy a valuetype from @src to @dest. This function must be used
6404 * when @klass contains references fields.
6407 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
6409 MONO_REQ_GC_UNSAFE_MODE;
6411 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
6415 * mono_value_copy_array:
6416 * @dest: destination array
6417 * @dest_idx: index in the @dest array
6418 * @src: source pointer
6419 * @count: number of items
6421 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
6422 * This function must be used when @klass contains references fields.
6423 * Overlap is handled.
6426 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
6428 MONO_REQ_GC_UNSAFE_MODE;
6430 int size = mono_array_element_size (dest->obj.vtable->klass);
6431 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
6432 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
6433 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
6437 * mono_object_get_domain:
6438 * @obj: object to query
6440 * Returns: the MonoDomain where the object is hosted
6443 mono_object_get_domain (MonoObject *obj)
6445 MONO_REQ_GC_UNSAFE_MODE;
6447 return mono_object_domain (obj);
6451 * mono_object_get_class:
6452 * @obj: object to query
6454 * Use this function to obtain the `MonoClass*` for a given `MonoObject`.
6456 * Returns: the MonoClass of the object.
6459 mono_object_get_class (MonoObject *obj)
6461 MONO_REQ_GC_UNSAFE_MODE;
6463 return mono_object_class (obj);
6466 * mono_object_get_size:
6467 * @o: object to query
6469 * Returns: the size, in bytes, of @o
6472 mono_object_get_size (MonoObject* o)
6474 MONO_REQ_GC_UNSAFE_MODE;
6476 MonoClass* klass = mono_object_class (o);
6477 if (klass == mono_defaults.string_class) {
6478 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
6479 } else if (o->vtable->rank) {
6480 MonoArray *array = (MonoArray*)o;
6481 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
6482 if (array->bounds) {
6485 size += sizeof (MonoArrayBounds) * o->vtable->rank;
6489 return mono_class_instance_size (klass);
6494 * mono_object_unbox:
6495 * @obj: object to unbox
6497 * Returns: a pointer to the start of the valuetype boxed in this
6500 * This method will assert if the object passed is not a valuetype.
6503 mono_object_unbox (MonoObject *obj)
6505 MONO_REQ_GC_UNSAFE_MODE;
6507 /* add assert for valuetypes? */
6508 g_assert (obj->vtable->klass->valuetype);
6509 return ((char*)obj) + sizeof (MonoObject);
6513 * mono_object_isinst:
6515 * @klass: a pointer to a class
6517 * Returns: @obj if @obj is derived from @klass or NULL otherwise.
6520 mono_object_isinst (MonoObject *obj_raw, MonoClass *klass)
6522 MONO_REQ_GC_UNSAFE_MODE;
6524 HANDLE_FUNCTION_ENTER ();
6525 MONO_HANDLE_DCL (MonoObject, obj);
6527 MonoObjectHandle result = mono_object_handle_isinst (obj, klass, &error);
6528 mono_error_cleanup (&error);
6529 HANDLE_FUNCTION_RETURN_OBJ (result);
6534 * mono_object_isinst_checked:
6536 * @klass: a pointer to a class
6537 * @error: set on error
6539 * Returns: @obj if @obj is derived from @klass or NULL if it isn't.
6540 * On failure returns NULL and sets @error.
6543 mono_object_isinst_checked (MonoObject *obj_raw, MonoClass *klass, MonoError *error)
6545 MONO_REQ_GC_UNSAFE_MODE;
6547 HANDLE_FUNCTION_ENTER ();
6548 mono_error_init (error);
6549 MONO_HANDLE_DCL (MonoObject, obj);
6550 MonoObjectHandle result = mono_object_handle_isinst (obj, klass, error);
6551 HANDLE_FUNCTION_RETURN_OBJ (result);
6555 * mono_object_handle_isinst:
6557 * @klass: a pointer to a class
6558 * @error: set on error
6560 * Returns: @obj if @obj is derived from @klass or NULL if it isn't.
6561 * On failure returns NULL and sets @error.
6564 mono_object_handle_isinst (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
6566 mono_error_init (error);
6569 mono_class_init (klass);
6571 if (mono_class_is_marshalbyref (klass) || mono_class_is_interface (klass)) {
6572 return mono_object_handle_isinst_mbyref (obj, klass, error);
6575 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6577 if (!MONO_HANDLE_IS_NULL (obj) && mono_class_is_assignable_from (klass, mono_handle_class (obj)))
6578 MONO_HANDLE_ASSIGN (result, obj);
6583 mono_object_isinst_mbyref (MonoObject *obj_raw, MonoClass *klass)
6585 MONO_REQ_GC_UNSAFE_MODE;
6587 HANDLE_FUNCTION_ENTER ();
6589 MONO_HANDLE_DCL (MonoObject, obj);
6590 MonoObjectHandle result = mono_object_handle_isinst_mbyref (obj, klass, &error);
6591 mono_error_cleanup (&error); /* FIXME better API that doesn't swallow the error */
6592 HANDLE_FUNCTION_RETURN_OBJ (result);
6596 mono_object_handle_isinst_mbyref (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
6598 mono_error_init (error);
6600 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6602 if (MONO_HANDLE_IS_NULL (obj))
6605 MonoVTable *vt = MONO_HANDLE_GETVAL (obj, vtable);
6607 if (mono_class_is_interface (klass)) {
6608 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
6609 MONO_HANDLE_ASSIGN (result, obj);
6613 /* casting an array one of the invariant interfaces that must act as such */
6614 if (klass->is_array_special_interface) {
6615 if (mono_class_is_assignable_from (klass, vt->klass)) {
6616 MONO_HANDLE_ASSIGN (result, obj);
6621 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
6622 else if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, mono_handle_class (obj))) {
6623 MONO_HANDLE_ASSIGN (result, obj);
6627 MonoClass *oklass = vt->klass;
6628 if (mono_class_is_transparent_proxy (oklass)){
6629 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), remote_class);
6630 oklass = remote_class->proxy_class;
6633 mono_class_setup_supertypes (klass);
6634 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass)) {
6635 MONO_HANDLE_ASSIGN (result, obj);
6639 #ifndef DISABLE_REMOTING
6640 if (mono_class_is_transparent_proxy (vt->klass))
6642 MonoBoolean custom_type_info = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), custom_type_info);
6643 if (!custom_type_info)
6645 MonoDomain *domain = mono_domain_get ();
6646 MonoObjectHandle rp = MONO_HANDLE_NEW (MonoObject, NULL);
6647 MONO_HANDLE_GET (rp, MONO_HANDLE_CAST (MonoTransparentProxy, obj), rp);
6648 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
6649 MonoMethod *im = NULL;
6652 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
6654 mono_error_set_not_supported (error, "Linked away.");
6657 im = mono_object_handle_get_virtual_method (rp, im, error);
6662 MonoReflectionTypeHandle reftype = mono_type_get_object_handle (domain, &klass->byval_arg, error);
6666 pa [0] = MONO_HANDLE_RAW (reftype);
6667 pa [1] = MONO_HANDLE_RAW (obj);
6668 MonoObject *res = mono_runtime_invoke_checked (im, rp, pa, error);
6672 if (*(MonoBoolean *) mono_object_unbox(res)) {
6673 /* Update the vtable of the remote type, so it can safely cast to this new type */
6674 mono_upgrade_remote_class (domain, obj, klass, error);
6677 MONO_HANDLE_ASSIGN (result, obj);
6680 #endif /* DISABLE_REMOTING */
6686 * mono_object_castclass_mbyref:
6688 * @klass: a pointer to a class
6690 * Returns: @obj if @obj is derived from @klass, returns NULL otherwise.
6693 mono_object_castclass_mbyref (MonoObject *obj_raw, MonoClass *klass)
6695 MONO_REQ_GC_UNSAFE_MODE;
6696 HANDLE_FUNCTION_ENTER ();
6698 MONO_HANDLE_DCL (MonoObject, obj);
6699 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6700 if (MONO_HANDLE_IS_NULL (obj))
6702 MONO_HANDLE_ASSIGN (result, mono_object_handle_isinst_mbyref (obj, klass, &error));
6703 mono_error_cleanup (&error);
6705 HANDLE_FUNCTION_RETURN_OBJ (result);
6709 MonoDomain *orig_domain;
6715 str_lookup (MonoDomain *domain, gpointer user_data)
6717 MONO_REQ_GC_UNSAFE_MODE;
6719 LDStrInfo *info = (LDStrInfo *)user_data;
6720 if (info->res || domain == info->orig_domain)
6722 info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
6726 mono_string_get_pinned (MonoString *str, MonoError *error)
6728 MONO_REQ_GC_UNSAFE_MODE;
6730 mono_error_init (error);
6732 /* We only need to make a pinned version of a string if this is a moving GC */
6733 if (!mono_gc_is_moving ())
6737 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
6738 news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
6740 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
6741 news->length = mono_string_length (str);
6743 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6749 mono_string_is_interned_lookup (MonoString *str, int insert, MonoError *error)
6751 MONO_REQ_GC_UNSAFE_MODE;
6753 MonoGHashTable *ldstr_table;
6754 MonoString *s, *res;
6757 mono_error_init (error);
6759 domain = ((MonoObject *)str)->vtable->domain;
6760 ldstr_table = domain->ldstr_table;
6762 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6768 /* Allocate outside the lock */
6770 s = mono_string_get_pinned (str, error);
6771 return_val_if_nok (error, NULL);
6774 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6779 mono_g_hash_table_insert (ldstr_table, s, s);
6784 LDStrInfo ldstr_info;
6785 ldstr_info.orig_domain = domain;
6786 ldstr_info.ins = str;
6787 ldstr_info.res = NULL;
6789 mono_domain_foreach (str_lookup, &ldstr_info);
6790 if (ldstr_info.res) {
6792 * the string was already interned in some other domain:
6793 * intern it in the current one as well.
6795 mono_g_hash_table_insert (ldstr_table, str, str);
6805 * mono_string_is_interned:
6806 * @o: String to probe
6808 * Returns whether the string has been interned.
6811 mono_string_is_interned (MonoString *o)
6814 MonoString *result = mono_string_is_interned_lookup (o, FALSE, &error);
6815 /* This function does not fail. */
6816 mono_error_assert_ok (&error);
6821 * mono_string_intern:
6822 * @o: String to intern
6824 * Interns the string passed.
6825 * Returns: The interned string.
6828 mono_string_intern (MonoString *str)
6831 MonoString *result = mono_string_intern_checked (str, &error);
6832 mono_error_assert_ok (&error);
6837 * mono_string_intern_checked:
6838 * @o: String to intern
6839 * @error: set on error.
6841 * Interns the string passed.
6842 * Returns: The interned string. On failure returns NULL and sets @error
6845 mono_string_intern_checked (MonoString *str, MonoError *error)
6847 MONO_REQ_GC_UNSAFE_MODE;
6849 mono_error_init (error);
6851 return mono_string_is_interned_lookup (str, TRUE, error);
6856 * @domain: the domain where the string will be used.
6857 * @image: a metadata context
6858 * @idx: index into the user string table.
6860 * Implementation for the ldstr opcode.
6861 * Returns: a loaded string from the @image/@idx combination.
6864 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
6867 MonoString *result = mono_ldstr_checked (domain, image, idx, &error);
6868 mono_error_cleanup (&error);
6873 * mono_ldstr_checked:
6874 * @domain: the domain where the string will be used.
6875 * @image: a metadata context
6876 * @idx: index into the user string table.
6877 * @error: set on error.
6879 * Implementation for the ldstr opcode.
6880 * Returns: a loaded string from the @image/@idx combination.
6881 * On failure returns NULL and sets @error.
6884 mono_ldstr_checked (MonoDomain *domain, MonoImage *image, guint32 idx, MonoError *error)
6886 MONO_REQ_GC_UNSAFE_MODE;
6887 mono_error_init (error);
6889 if (image->dynamic) {
6890 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL, error);
6893 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6894 return NULL; /*FIXME we should probably be raising an exception here*/
6895 MonoString *str = mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx), error);
6901 * mono_ldstr_metadata_sig
6902 * @domain: the domain for the string
6903 * @sig: the signature of a metadata string
6904 * @error: set on error
6906 * Returns: a MonoString for a string stored in the metadata. On
6907 * failure returns NULL and sets @error.
6910 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error)
6912 MONO_REQ_GC_UNSAFE_MODE;
6914 mono_error_init (error);
6915 const char *str = sig;
6916 MonoString *o, *interned;
6919 len2 = mono_metadata_decode_blob_size (str, &str);
6922 o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, error);
6923 return_val_if_nok (error, NULL);
6924 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
6927 guint16 *p2 = (guint16*)mono_string_chars (o);
6928 for (i = 0; i < len2; ++i) {
6929 *p2 = GUINT16_FROM_LE (*p2);
6935 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6938 return interned; /* o will get garbage collected */
6940 o = mono_string_get_pinned (o, error);
6943 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6945 mono_g_hash_table_insert (domain->ldstr_table, o, o);
6957 * Same as mono_ldstr, but return a NULL terminated utf8 string instead
6961 mono_ldstr_utf8 (MonoImage *image, guint32 idx, MonoError *error)
6967 GError *gerror = NULL;
6969 mono_error_init (error);
6971 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6972 return NULL; /*FIXME we should probably be raising an exception here*/
6973 str = mono_metadata_user_string (image, idx);
6975 len2 = mono_metadata_decode_blob_size (str, &str);
6978 as = g_utf16_to_utf8 ((guint16*)str, len2, NULL, &written, &gerror);
6980 mono_error_set_argument (error, "string", "%s", gerror->message);
6981 g_error_free (gerror);
6984 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6985 if (len2 > written) {
6986 /* allocate the total length and copy the part of the string that has been converted */
6987 char *as2 = (char *)g_malloc0 (len2);
6988 memcpy (as2, as, written);
6997 * mono_string_to_utf8:
6998 * @s: a System.String
7000 * Returns the UTF8 representation for @s.
7001 * The resulting buffer needs to be freed with mono_free().
7003 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
7006 mono_string_to_utf8 (MonoString *s)
7008 MONO_REQ_GC_UNSAFE_MODE;
7011 char *result = mono_string_to_utf8_checked (s, &error);
7013 if (!is_ok (&error)) {
7014 mono_error_cleanup (&error);
7021 * mono_string_to_utf8_checked:
7022 * @s: a System.String
7023 * @error: a MonoError.
7025 * Converts a MonoString to its UTF8 representation. May fail; check
7026 * @error to determine whether the conversion was successful.
7027 * The resulting buffer should be freed with mono_free().
7030 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
7032 MONO_REQ_GC_UNSAFE_MODE;
7036 GError *gerror = NULL;
7038 mono_error_init (error);
7044 return g_strdup ("");
7046 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
7048 mono_error_set_argument (error, "string", "%s", gerror->message);
7049 g_error_free (gerror);
7052 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
7053 if (s->length > written) {
7054 /* allocate the total length and copy the part of the string that has been converted */
7055 char *as2 = (char *)g_malloc0 (s->length);
7056 memcpy (as2, as, written);
7065 mono_string_handle_to_utf8 (MonoStringHandle s, MonoError *error)
7067 return mono_string_to_utf8_checked (MONO_HANDLE_RAW (s), error);
7071 * mono_string_to_utf8_ignore:
7074 * Converts a MonoString to its UTF8 representation. Will ignore
7075 * invalid surrogate pairs.
7076 * The resulting buffer should be freed with mono_free().
7080 mono_string_to_utf8_ignore (MonoString *s)
7082 MONO_REQ_GC_UNSAFE_MODE;
7091 return g_strdup ("");
7093 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
7095 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
7096 if (s->length > written) {
7097 /* allocate the total length and copy the part of the string that has been converted */
7098 char *as2 = (char *)g_malloc0 (s->length);
7099 memcpy (as2, as, written);
7108 * mono_string_to_utf8_image_ignore:
7109 * @s: a System.String
7111 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
7114 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
7116 MONO_REQ_GC_UNSAFE_MODE;
7118 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
7122 * mono_string_to_utf8_mp_ignore:
7123 * @s: a System.String
7125 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
7128 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
7130 MONO_REQ_GC_UNSAFE_MODE;
7132 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
7137 * mono_string_to_utf16:
7140 * Return an null-terminated array of the utf-16 chars
7141 * contained in @s. The result must be freed with g_free().
7142 * This is a temporary helper until our string implementation
7143 * is reworked to always include the null terminating char.
7146 mono_string_to_utf16 (MonoString *s)
7148 MONO_REQ_GC_UNSAFE_MODE;
7155 as = (char *)g_malloc ((s->length * 2) + 2);
7156 as [(s->length * 2)] = '\0';
7157 as [(s->length * 2) + 1] = '\0';
7160 return (gunichar2 *)(as);
7163 memcpy (as, mono_string_chars(s), s->length * 2);
7164 return (gunichar2 *)(as);
7168 * mono_string_to_utf32:
7171 * Return an null-terminated array of the UTF-32 (UCS-4) chars
7172 * contained in @s. The result must be freed with g_free().
7175 mono_string_to_utf32 (MonoString *s)
7177 MONO_REQ_GC_UNSAFE_MODE;
7179 mono_unichar4 *utf32_output = NULL;
7180 GError *error = NULL;
7181 glong items_written;
7186 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
7189 g_error_free (error);
7191 return utf32_output;
7195 * mono_string_from_utf16:
7196 * @data: the UTF16 string (LPWSTR) to convert
7198 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
7200 * Returns: a MonoString.
7203 mono_string_from_utf16 (gunichar2 *data)
7206 MonoString *result = mono_string_from_utf16_checked (data, &error);
7207 mono_error_cleanup (&error);
7212 * mono_string_from_utf16_checked:
7213 * @data: the UTF16 string (LPWSTR) to convert
7214 * @error: set on error
7216 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
7218 * Returns: a MonoString. On failure sets @error and returns NULL.
7221 mono_string_from_utf16_checked (gunichar2 *data, MonoError *error)
7224 MONO_REQ_GC_UNSAFE_MODE;
7226 mono_error_init (error);
7227 MonoDomain *domain = mono_domain_get ();
7233 while (data [len]) len++;
7235 return mono_string_new_utf16_checked (domain, data, len, error);
7239 * mono_string_from_utf32:
7240 * @data: the UTF32 string (LPWSTR) to convert
7242 * Converts a UTF32 (UCS-4)to a MonoString.
7244 * Returns: a MonoString.
7247 mono_string_from_utf32 (mono_unichar4 *data)
7250 MonoString *result = mono_string_from_utf32_checked (data, &error);
7251 mono_error_cleanup (&error);
7256 * mono_string_from_utf32_checked:
7257 * @data: the UTF32 string (LPWSTR) to convert
7258 * @error: set on error
7260 * Converts a UTF32 (UCS-4)to a MonoString.
7262 * Returns: a MonoString. On failure returns NULL and sets @error.
7265 mono_string_from_utf32_checked (mono_unichar4 *data, MonoError *error)
7267 MONO_REQ_GC_UNSAFE_MODE;
7269 mono_error_init (error);
7270 MonoString* result = NULL;
7271 mono_unichar2 *utf16_output = NULL;
7272 GError *gerror = NULL;
7273 glong items_written;
7279 while (data [len]) len++;
7281 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &gerror);
7284 g_error_free (gerror);
7286 result = mono_string_from_utf16_checked (utf16_output, error);
7287 g_free (utf16_output);
7292 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
7294 MONO_REQ_GC_UNSAFE_MODE;
7301 r = mono_string_to_utf8_ignore (s);
7303 r = mono_string_to_utf8_checked (s, error);
7304 if (!mono_error_ok (error))
7311 len = strlen (r) + 1;
7313 mp_s = (char *)mono_mempool_alloc (mp, len);
7315 mp_s = (char *)mono_image_alloc (image, len);
7317 memcpy (mp_s, r, len);
7325 * mono_string_to_utf8_image:
7326 * @s: a System.String
7328 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
7331 mono_string_to_utf8_image (MonoImage *image, MonoStringHandle s, MonoError *error)
7333 MONO_REQ_GC_UNSAFE_MODE;
7335 return mono_string_to_utf8_internal (NULL, image, MONO_HANDLE_RAW (s), FALSE, error); /* FIXME pin the string */
7339 * mono_string_to_utf8_mp:
7340 * @s: a System.String
7342 * Same as mono_string_to_utf8, but allocate the string from a mempool.
7345 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
7347 MONO_REQ_GC_UNSAFE_MODE;
7349 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
7353 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
7356 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
7358 eh_callbacks = *cbs;
7361 MonoRuntimeExceptionHandlingCallbacks *
7362 mono_get_eh_callbacks (void)
7364 return &eh_callbacks;
7368 * mono_raise_exception:
7369 * @ex: exception object
7371 * Signal the runtime that the exception @ex has been raised in unmanaged code.
7374 mono_raise_exception (MonoException *ex)
7376 MONO_REQ_GC_UNSAFE_MODE;
7379 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
7380 * that will cause gcc to omit the function epilog, causing problems when
7381 * the JIT tries to walk the stack, since the return address on the stack
7382 * will point into the next function in the executable, not this one.
7384 eh_callbacks.mono_raise_exception (ex);
7388 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
7390 MONO_REQ_GC_UNSAFE_MODE;
7392 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
7396 * mono_wait_handle_new:
7397 * @domain: Domain where the object will be created
7398 * @handle: Handle for the wait handle
7399 * @error: set on error.
7401 * Returns: A new MonoWaitHandle created in the given domain for the
7402 * given handle. On failure returns NULL and sets @rror.
7405 mono_wait_handle_new (MonoDomain *domain, HANDLE handle, MonoError *error)
7407 MONO_REQ_GC_UNSAFE_MODE;
7409 MonoWaitHandle *res;
7410 gpointer params [1];
7411 static MonoMethod *handle_set;
7413 mono_error_init (error);
7414 res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, error);
7415 return_val_if_nok (error, NULL);
7417 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
7419 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
7421 params [0] = &handle;
7423 mono_runtime_invoke_checked (handle_set, res, params, error);
7428 mono_wait_handle_get_handle (MonoWaitHandle *handle)
7430 MONO_REQ_GC_UNSAFE_MODE;
7432 static MonoClassField *f_safe_handle = NULL;
7435 if (!f_safe_handle) {
7436 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safeWaitHandle");
7437 g_assert (f_safe_handle);
7440 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
7446 mono_runtime_capture_context (MonoDomain *domain, MonoError *error)
7448 MONO_REQ_GC_UNSAFE_MODE;
7450 RuntimeInvokeFunction runtime_invoke;
7452 mono_error_init (error);
7454 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
7455 MonoMethod *method = mono_get_context_capture_method ();
7456 MonoMethod *wrapper;
7459 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
7460 domain->capture_context_runtime_invoke = mono_compile_method_checked (wrapper, error);
7461 return_val_if_nok (error, NULL);
7462 domain->capture_context_method = mono_compile_method_checked (method, error);
7463 return_val_if_nok (error, NULL);
7466 runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
7468 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
7471 * mono_async_result_new:
7472 * @domain:domain where the object will be created.
7473 * @handle: wait handle.
7474 * @state: state to pass to AsyncResult
7475 * @data: C closure data.
7476 * @error: set on error.
7478 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
7479 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
7480 * On failure returns NULL and sets @error.
7484 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data, MonoError *error)
7486 MONO_REQ_GC_UNSAFE_MODE;
7488 mono_error_init (error);
7489 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, error);
7490 return_val_if_nok (error, NULL);
7491 MonoObject *context = mono_runtime_capture_context (domain, error);
7492 return_val_if_nok (error, NULL);
7493 /* we must capture the execution context from the original thread */
7495 MONO_OBJECT_SETREF (res, execution_context, context);
7496 /* note: result may be null if the flow is suppressed */
7499 res->data = (void **)data;
7500 MONO_OBJECT_SETREF (res, object_data, object_data);
7501 MONO_OBJECT_SETREF (res, async_state, state);
7502 MonoWaitHandle *wait_handle = mono_wait_handle_new (domain, handle, error);
7503 return_val_if_nok (error, NULL);
7505 MONO_OBJECT_SETREF (res, handle, (MonoObject *) wait_handle);
7507 res->sync_completed = FALSE;
7508 res->completed = FALSE;
7514 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
7516 MONO_REQ_GC_UNSAFE_MODE;
7523 g_assert (ares->async_delegate);
7525 ac = (MonoAsyncCall*) ares->object_data;
7527 res = mono_runtime_delegate_invoke_checked (ares->async_delegate, (void**) &ares->async_state, &error);
7528 if (mono_error_set_pending_exception (&error))
7531 gpointer wait_event = NULL;
7533 ac->msg->exc = NULL;
7535 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args, &error);
7537 /* The exit side of the invoke must not be aborted as it would leave the runtime in an undefined state */
7538 mono_threads_begin_abort_protected_block ();
7540 if (!ac->msg->exc) {
7541 MonoException *ex = mono_error_convert_to_exception (&error);
7542 ac->msg->exc = (MonoObject *)ex;
7544 mono_error_cleanup (&error);
7547 MONO_OBJECT_SETREF (ac, res, res);
7549 mono_monitor_enter ((MonoObject*) ares);
7550 ares->completed = 1;
7552 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
7553 mono_monitor_exit ((MonoObject*) ares);
7555 if (wait_event != NULL)
7556 mono_w32event_set (wait_event);
7558 mono_error_init (&error); //the else branch would leave it in an undefined state
7560 mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
7562 mono_threads_end_abort_protected_block ();
7564 if (mono_error_set_pending_exception (&error))
7572 mono_message_init (MonoDomain *domain,
7573 MonoMethodMessage *this_obj,
7574 MonoReflectionMethod *method,
7575 MonoArray *out_args,
7578 MONO_REQ_GC_UNSAFE_MODE;
7580 static MonoMethod *init_message_method = NULL;
7582 if (!init_message_method) {
7583 init_message_method = mono_class_get_method_from_name (mono_defaults.mono_method_message_class, "InitMessage", 2);
7584 g_assert (init_message_method != NULL);
7587 mono_error_init (error);
7588 /* FIXME set domain instead? */
7589 g_assert (domain == mono_domain_get ());
7596 mono_runtime_invoke_checked (init_message_method, this_obj, args, error);
7597 return is_ok (error);
7600 #ifndef DISABLE_REMOTING
7602 * mono_remoting_invoke:
7603 * @real_proxy: pointer to a RealProxy object
7604 * @msg: The MonoMethodMessage to execute
7605 * @exc: used to store exceptions
7606 * @out_args: used to store output arguments
7608 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
7609 * IMessage interface and it is not trivial to extract results from there. So
7610 * we call an helper method PrivateInvoke instead of calling
7611 * RealProxy::Invoke() directly.
7613 * Returns: the result object.
7616 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, MonoObject **exc, MonoArray **out_args, MonoError *error)
7618 MONO_REQ_GC_UNSAFE_MODE;
7621 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
7626 mono_error_init (error);
7628 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
7631 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
7633 mono_error_set_not_supported (error, "Linked away.");
7636 real_proxy->vtable->domain->private_invoke_method = im;
7639 pa [0] = real_proxy;
7644 o = mono_runtime_try_invoke (im, NULL, pa, exc, error);
7645 return_val_if_nok (error, NULL);
7652 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
7653 MonoObject **exc, MonoArray **out_args, MonoError *error)
7655 MONO_REQ_GC_UNSAFE_MODE;
7657 static MonoClass *object_array_klass;
7658 mono_error_init (error);
7662 MonoMethodSignature *sig;
7664 int i, j, outarg_count = 0;
7666 #ifndef DISABLE_REMOTING
7667 if (target && mono_object_is_transparent_proxy (target)) {
7668 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
7669 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7670 target = tp->rp->unwrapped_server;
7672 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args, error);
7677 domain = mono_domain_get ();
7678 method = msg->method->method;
7679 sig = mono_method_signature (method);
7681 for (i = 0; i < sig->param_count; i++) {
7682 if (sig->params [i]->byref)
7686 if (!object_array_klass) {
7689 klass = mono_array_class_get (mono_defaults.object_class, 1);
7692 mono_memory_barrier ();
7693 object_array_klass = klass;
7696 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, error);
7697 return_val_if_nok (error, NULL);
7699 mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
7702 MonoObject *ret = mono_runtime_try_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc, error);
7703 return_val_if_nok (error, NULL);
7705 for (i = 0, j = 0; i < sig->param_count; i++) {
7706 if (sig->params [i]->byref) {
7708 arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
7709 mono_array_setref (*out_args, j, arg);
7718 * prepare_to_string_method:
7720 * @target: Set to @obj or unboxed value if a valuetype
7722 * Returns: the ToString override for @obj. If @obj is a valuetype, @target is unboxed otherwise it's @obj.
7725 prepare_to_string_method (MonoObject *obj, void **target)
7727 MONO_REQ_GC_UNSAFE_MODE;
7729 static MonoMethod *to_string = NULL;
7737 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
7739 method = mono_object_get_virtual_method (obj, to_string);
7741 // Unbox value type if needed
7742 if (mono_class_is_valuetype (mono_method_get_class (method))) {
7743 *target = mono_object_unbox (obj);
7749 * mono_object_to_string:
7751 * @exc: Any exception thrown by ToString (). May be NULL.
7753 * Returns: the result of calling ToString () on an object.
7756 mono_object_to_string (MonoObject *obj, MonoObject **exc)
7759 MonoString *s = NULL;
7761 MonoMethod *method = prepare_to_string_method (obj, &target);
7763 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
7764 if (*exc == NULL && !mono_error_ok (&error))
7765 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
7767 mono_error_cleanup (&error);
7769 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
7770 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
7777 * mono_object_to_string_checked:
7779 * @error: Set on error.
7781 * Returns: the result of calling ToString () on an object. If the
7782 * method cannot be invoked or if it raises an exception, sets @error
7786 mono_object_to_string_checked (MonoObject *obj, MonoError *error)
7788 mono_error_init (error);
7790 MonoMethod *method = prepare_to_string_method (obj, &target);
7791 return (MonoString*) mono_runtime_invoke_checked (method, target, NULL, error);
7795 * mono_object_try_to_string:
7797 * @exc: Any exception thrown by ToString (). Must not be NULL.
7798 * @error: Set if method cannot be invoked.
7800 * Returns: the result of calling ToString () on an object. If the
7801 * method cannot be invoked sets @error, if it raises an exception sets @exc,
7805 mono_object_try_to_string (MonoObject *obj, MonoObject **exc, MonoError *error)
7808 mono_error_init (error);
7810 MonoMethod *method = prepare_to_string_method (obj, &target);
7811 return (MonoString*) mono_runtime_try_invoke (method, target, NULL, exc, error);
7817 get_native_backtrace (MonoException *exc_raw)
7819 HANDLE_FUNCTION_ENTER ();
7820 MONO_HANDLE_DCL(MonoException, exc);
7821 char * trace = mono_exception_handle_get_native_backtrace (exc);
7822 HANDLE_FUNCTION_RETURN_VAL (trace);
7826 * mono_print_unhandled_exception:
7827 * @exc: The exception
7829 * Prints the unhandled exception.
7832 mono_print_unhandled_exception (MonoObject *exc)
7834 MONO_REQ_GC_UNSAFE_MODE;
7837 char *message = (char*)"";
7838 gboolean free_message = FALSE;
7841 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
7842 message = g_strdup ("OutOfMemoryException");
7843 free_message = TRUE;
7844 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
7845 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
7846 free_message = TRUE;
7849 if (((MonoException*)exc)->native_trace_ips) {
7850 message = get_native_backtrace ((MonoException*)exc);
7851 free_message = TRUE;
7853 MonoObject *other_exc = NULL;
7854 str = mono_object_try_to_string (exc, &other_exc, &error);
7855 if (other_exc == NULL && !is_ok (&error))
7856 other_exc = (MonoObject*)mono_error_convert_to_exception (&error);
7858 mono_error_cleanup (&error);
7860 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
7861 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
7863 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
7864 original_backtrace, nested_backtrace);
7866 g_free (original_backtrace);
7867 g_free (nested_backtrace);
7868 free_message = TRUE;
7870 message = mono_string_to_utf8_checked (str, &error);
7871 if (!mono_error_ok (&error)) {
7872 mono_error_cleanup (&error);
7873 message = (char *) "";
7875 free_message = TRUE;
7882 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
7883 * exc->vtable->klass->name, message);
7885 g_printerr ("\nUnhandled Exception:\n%s\n", message);
7892 * mono_delegate_ctor_with_method:
7893 * @this: pointer to an uninitialized delegate object
7894 * @target: target object
7895 * @addr: pointer to native code
7897 * @error: set on error.
7899 * Initialize a delegate and sets a specific method, not the one
7900 * associated with addr. This is useful when sharing generic code.
7901 * In that case addr will most probably not be associated with the
7902 * correct instantiation of the method.
7903 * On failure returns FALSE and sets @error.
7906 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method, MonoError *error)
7908 MONO_REQ_GC_UNSAFE_MODE;
7910 mono_error_init (error);
7911 MonoDelegate *delegate = (MonoDelegate *)this_obj;
7913 g_assert (this_obj);
7916 g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
7919 delegate->method = method;
7921 mono_stats.delegate_creations++;
7923 #ifndef DISABLE_REMOTING
7924 if (target && mono_object_is_transparent_proxy (target)) {
7926 method = mono_marshal_get_remoting_invoke (method);
7927 delegate->method_ptr = mono_compile_method_checked (method, error);
7928 return_val_if_nok (error, FALSE);
7929 MONO_OBJECT_SETREF (delegate, target, target);
7933 delegate->method_ptr = addr;
7934 MONO_OBJECT_SETREF (delegate, target, target);
7937 delegate->invoke_impl = callbacks.create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
7938 if (callbacks.init_delegate)
7939 callbacks.init_delegate (delegate);
7944 * mono_delegate_ctor:
7945 * @this: pointer to an uninitialized delegate object
7946 * @target: target object
7947 * @addr: pointer to native code
7948 * @error: set on error.
7950 * This is used to initialize a delegate.
7951 * On failure returns FALSE and sets @error.
7954 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoError *error)
7956 MONO_REQ_GC_UNSAFE_MODE;
7958 mono_error_init (error);
7959 MonoDomain *domain = mono_domain_get ();
7961 MonoMethod *method = NULL;
7965 ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
7967 if (!ji && domain != mono_get_root_domain ())
7968 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
7970 method = mono_jit_info_get_method (ji);
7971 g_assert (!mono_class_is_gtd (method->klass));
7974 return mono_delegate_ctor_with_method (this_obj, target, addr, method, error);
7978 * mono_method_call_message_new:
7979 * @method: method to encapsulate
7980 * @params: parameters to the method
7981 * @invoke: optional, delegate invoke.
7982 * @cb: async callback delegate.
7983 * @state: state passed to the async callback.
7984 * @error: set on error.
7986 * Translates arguments pointers into a MonoMethodMessage.
7987 * On failure returns NULL and sets @error.
7990 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
7991 MonoDelegate **cb, MonoObject **state, MonoError *error)
7993 MONO_REQ_GC_UNSAFE_MODE;
7995 mono_error_init (error);
7997 MonoDomain *domain = mono_domain_get ();
7998 MonoMethodSignature *sig = mono_method_signature (method);
7999 MonoMethodMessage *msg;
8002 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8003 return_val_if_nok (error, NULL);
8006 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, error);
8007 return_val_if_nok (error, NULL);
8008 mono_message_init (domain, msg, rm, NULL, error);
8009 return_val_if_nok (error, NULL);
8010 count = sig->param_count - 2;
8012 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
8013 return_val_if_nok (error, NULL);
8014 mono_message_init (domain, msg, rm, NULL, error);
8015 return_val_if_nok (error, NULL);
8016 count = sig->param_count;
8019 for (i = 0; i < count; i++) {
8024 if (sig->params [i]->byref)
8025 vpos = *((gpointer *)params [i]);
8029 klass = mono_class_from_mono_type (sig->params [i]);
8031 if (klass->valuetype) {
8032 arg = mono_value_box_checked (domain, klass, vpos, error);
8033 return_val_if_nok (error, NULL);
8035 arg = *((MonoObject **)vpos);
8037 mono_array_setref (msg->args, i, arg);
8040 if (cb != NULL && state != NULL) {
8041 *cb = *((MonoDelegate **)params [i]);
8043 *state = *((MonoObject **)params [i]);
8050 * mono_method_return_message_restore:
8052 * Restore results from message based processing back to arguments pointers
8055 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args, MonoError *error)
8057 MONO_REQ_GC_UNSAFE_MODE;
8059 mono_error_init (error);
8061 MonoMethodSignature *sig = mono_method_signature (method);
8062 int i, j, type, size, out_len;
8064 if (out_args == NULL)
8066 out_len = mono_array_length (out_args);
8070 for (i = 0, j = 0; i < sig->param_count; i++) {
8071 MonoType *pt = sig->params [i];
8076 mono_error_set_execution_engine (error, "The proxy call returned an incorrect number of output arguments");
8080 arg = (char *)mono_array_get (out_args, gpointer, j);
8083 g_assert (type != MONO_TYPE_VOID);
8085 if (MONO_TYPE_IS_REFERENCE (pt)) {
8086 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
8089 MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
8090 size = mono_class_value_size (klass, NULL);
8091 if (klass->has_references)
8092 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
8094 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
8096 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
8097 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
8106 #ifndef DISABLE_REMOTING
8109 * mono_load_remote_field:
8110 * @this: pointer to an object
8111 * @klass: klass of the object containing @field
8112 * @field: the field to load
8113 * @res: a storage to store the result
8115 * This method is called by the runtime on attempts to load fields of
8116 * transparent proxy objects. @this points to such TP, @klass is the class of
8117 * the object containing @field. @res is a storage location which can be
8118 * used to store the result.
8120 * Returns: an address pointing to the value of field.
8123 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
8126 gpointer result = mono_load_remote_field_checked (this_obj, klass, field, res, &error);
8127 mono_error_cleanup (&error);
8132 * mono_load_remote_field_checked:
8133 * @this: pointer to an object
8134 * @klass: klass of the object containing @field
8135 * @field: the field to load
8136 * @res: a storage to store the result
8137 * @error: set on error
8139 * This method is called by the runtime on attempts to load fields of
8140 * transparent proxy objects. @this points to such TP, @klass is the class of
8141 * the object containing @field. @res is a storage location which can be
8142 * used to store the result.
8144 * Returns: an address pointing to the value of field. On failure returns NULL and sets @error.
8147 mono_load_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res, MonoError *error)
8149 MONO_REQ_GC_UNSAFE_MODE;
8151 static MonoMethod *getter = NULL;
8153 mono_error_init (error);
8155 MonoDomain *domain = mono_domain_get ();
8156 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8157 MonoClass *field_class;
8158 MonoMethodMessage *msg;
8159 MonoArray *out_args;
8163 g_assert (mono_object_is_transparent_proxy (this_obj));
8164 g_assert (res != NULL);
8166 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8167 mono_field_get_value (tp->rp->unwrapped_server, field, res);
8172 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
8174 mono_error_set_not_supported (error, "Linked away.");
8179 field_class = mono_class_from_mono_type (field->type);
8181 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8182 return_val_if_nok (error, NULL);
8183 out_args = mono_array_new_checked (domain, mono_defaults.object_class, 1, error);
8184 return_val_if_nok (error, NULL);
8185 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, error);
8186 return_val_if_nok (error, NULL);
8187 mono_message_init (domain, msg, rm, out_args, error);
8188 return_val_if_nok (error, NULL);
8190 full_name = mono_type_get_full_name (klass);
8191 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
8192 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
8195 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8196 return_val_if_nok (error, NULL);
8199 mono_error_set_exception_instance (error, (MonoException *)exc);
8203 if (mono_array_length (out_args) == 0)
8206 mono_gc_wbarrier_generic_store (res, mono_array_get (out_args, MonoObject *, 0));
8208 if (field_class->valuetype) {
8209 return ((char *)*res) + sizeof (MonoObject);
8215 * mono_load_remote_field_new:
8220 * Missing documentation.
8223 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
8227 MonoObject *result = mono_load_remote_field_new_checked (this_obj, klass, field, &error);
8228 mono_error_cleanup (&error);
8233 * mono_load_remote_field_new_checked:
8234 * @this: pointer to an object
8235 * @klass: klass of the object containing @field
8236 * @field: the field to load
8237 * @error: set on error.
8239 * This method is called by the runtime on attempts to load fields of
8240 * transparent proxy objects. @this points to such TP, @klass is the class of
8241 * the object containing @field.
8243 * Returns: a freshly allocated object containing the value of the field. On failure returns NULL and sets @error.
8246 mono_load_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoError *error)
8248 MONO_REQ_GC_UNSAFE_MODE;
8250 mono_error_init (error);
8252 static MonoMethod *tp_load = NULL;
8254 g_assert (mono_object_is_transparent_proxy (this_obj));
8257 tp_load = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "LoadRemoteFieldNew", -1);
8259 mono_error_set_not_supported (error, "Linked away.");
8264 /* MonoType *type = mono_class_get_type (klass); */
8270 return mono_runtime_invoke_checked (tp_load, this_obj, args, error);
8274 * mono_store_remote_field:
8275 * @this_obj: pointer to an object
8276 * @klass: klass of the object containing @field
8277 * @field: the field to load
8278 * @val: the value/object to store
8280 * This method is called by the runtime on attempts to store fields of
8281 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
8282 * the object containing @field. @val is the new value to store in @field.
8285 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
8288 (void) mono_store_remote_field_checked (this_obj, klass, field, val, &error);
8289 mono_error_cleanup (&error);
8293 * mono_store_remote_field_checked:
8294 * @this_obj: pointer to an object
8295 * @klass: klass of the object containing @field
8296 * @field: the field to load
8297 * @val: the value/object to store
8298 * @error: set on error
8300 * This method is called by the runtime on attempts to store fields of
8301 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
8302 * the object containing @field. @val is the new value to store in @field.
8304 * Returns: on success returns TRUE, on failure returns FALSE and sets @error.
8307 mono_store_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val, MonoError *error)
8310 MONO_REQ_GC_UNSAFE_MODE;
8312 mono_error_init (error);
8314 MonoDomain *domain = mono_domain_get ();
8315 MonoClass *field_class;
8318 g_assert (mono_object_is_transparent_proxy (this_obj));
8320 field_class = mono_class_from_mono_type (field->type);
8322 if (field_class->valuetype) {
8323 arg = mono_value_box_checked (domain, field_class, val, error);
8324 return_val_if_nok (error, FALSE);
8326 arg = *((MonoObject**)val);
8329 return mono_store_remote_field_new_checked (this_obj, klass, field, arg, error);
8333 * mono_store_remote_field_new:
8339 * Missing documentation
8342 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
8345 (void) mono_store_remote_field_new_checked (this_obj, klass, field, arg, &error);
8346 mono_error_cleanup (&error);
8350 * mono_store_remote_field_new_checked:
8357 * Missing documentation
8360 mono_store_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg, MonoError *error)
8362 MONO_REQ_GC_UNSAFE_MODE;
8364 static MonoMethod *tp_store = NULL;
8366 mono_error_init (error);
8368 g_assert (mono_object_is_transparent_proxy (this_obj));
8371 tp_store = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "StoreRemoteField", -1);
8373 mono_error_set_not_supported (error, "Linked away.");
8383 mono_runtime_invoke_checked (tp_store, this_obj, args, error);
8384 return is_ok (error);
8389 * mono_create_ftnptr:
8391 * Given a function address, create a function descriptor for it.
8392 * This is only needed on some platforms.
8395 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
8397 return callbacks.create_ftnptr (domain, addr);
8401 * mono_get_addr_from_ftnptr:
8403 * Given a pointer to a function descriptor, return the function address.
8404 * This is only needed on some platforms.
8407 mono_get_addr_from_ftnptr (gpointer descr)
8409 return callbacks.get_addr_from_ftnptr (descr);
8413 * mono_string_chars:
8416 * Returns a pointer to the UCS16 characters stored in the MonoString
8419 mono_string_chars (MonoString *s)
8421 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
8427 * mono_string_length:
8430 * Returns the lenght in characters of the string
8433 mono_string_length (MonoString *s)
8435 MONO_REQ_GC_UNSAFE_MODE;
8441 * mono_string_handle_length:
8444 * Returns the lenght in characters of the string
8447 mono_string_handle_length (MonoStringHandle s)
8449 MONO_REQ_GC_UNSAFE_MODE;
8451 return MONO_HANDLE_GETVAL (s, length);
8456 * mono_array_length:
8457 * @array: a MonoArray*
8459 * Returns the total number of elements in the array. This works for
8460 * both vectors and multidimensional arrays.
8463 mono_array_length (MonoArray *array)
8465 MONO_REQ_GC_UNSAFE_MODE;
8467 return array->max_length;
8471 * mono_array_addr_with_size:
8472 * @array: a MonoArray*
8473 * @size: size of the array elements
8474 * @idx: index into the array
8476 * Use this function to obtain the address for the @idx item on the
8477 * @array containing elements of size @size.
8479 * This method performs no bounds checking or type checking.
8481 * Returns the address of the @idx element in the array.
8484 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
8486 MONO_REQ_GC_UNSAFE_MODE;
8488 return ((char*)(array)->vector) + size * idx;
8493 mono_glist_to_array (GList *list, MonoClass *eclass, MonoError *error)
8495 MonoDomain *domain = mono_domain_get ();
8499 mono_error_init (error);
8503 len = g_list_length (list);
8504 res = mono_array_new_checked (domain, eclass, len, error);
8505 return_val_if_nok (error, NULL);
8507 for (i = 0; list; list = list->next, i++)
8508 mono_array_set (res, gpointer, i, list->data);
8515 * The following section is purely to declare prototypes and
8516 * document the API, as these C files are processed by our
8522 * @array: array to alter
8523 * @element_type: A C type name, this macro will use the sizeof(type) to determine the element size
8524 * @index: index into the array
8525 * @value: value to set
8527 * Value Type version: This sets the @index's element of the @array
8528 * with elements of size sizeof(type) to the provided @value.
8530 * This macro does not attempt to perform type checking or bounds checking.
8532 * Use this to set value types in a `MonoArray`.
8534 void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
8539 * mono_array_setref:
8540 * @array: array to alter
8541 * @index: index into the array
8542 * @value: value to set
8544 * Reference Type version: This sets the @index's element of the
8545 * @array with elements of size sizeof(type) to the provided @value.
8547 * This macro does not attempt to perform type checking or bounds checking.
8549 * Use this to reference types in a `MonoArray`.
8551 void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
8557 * @array: array on which to operate on
8558 * @element_type: C element type (example: MonoString *, int, MonoObject *)
8559 * @index: index into the array
8561 * Use this macro to retrieve the @index element of an @array and
8562 * extract the value assuming that the elements of the array match
8563 * the provided type value.
8565 * This method can be used with both arrays holding value types and
8566 * reference types. For reference types, the @type parameter should
8567 * be a `MonoObject*` or any subclass of it, like `MonoString*`.
8569 * This macro does not attempt to perform type checking or bounds checking.
8571 * Returns: The element at the @index position in the @array.
8573 Type mono_array_get (MonoArray *array, Type element_type, uintptr_t index)