3 * Object creation for the Mono runtime
6 * Miguel de Icaza (miguel@ximian.com)
7 * Paolo Molaro (lupus@ximian.com)
9 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10 * Copyright 2004-2011 Novell, Inc (http://www.novell.com)
11 * Copyright 2001 Xamarin Inc (http://www.xamarin.com)
12 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
21 #include <mono/metadata/mono-endian.h>
22 #include <mono/metadata/tabledefs.h>
23 #include <mono/metadata/tokentype.h>
24 #include <mono/metadata/loader.h>
25 #include <mono/metadata/object.h>
26 #include <mono/metadata/gc-internals.h>
27 #include <mono/metadata/exception.h>
28 #include <mono/metadata/exception-internals.h>
29 #include <mono/metadata/domain-internals.h>
30 #include "mono/metadata/metadata-internals.h"
31 #include "mono/metadata/class-internals.h"
32 #include <mono/metadata/assembly.h>
33 #include <mono/metadata/marshal.h>
34 #include "mono/metadata/debug-helpers.h"
35 #include <mono/metadata/threads.h>
36 #include <mono/metadata/threads-types.h>
37 #include <mono/metadata/environment.h>
38 #include "mono/metadata/profiler-private.h"
39 #include "mono/metadata/security-manager.h"
40 #include <mono/metadata/verify-internals.h>
41 #include <mono/metadata/reflection-internals.h>
42 #include <mono/metadata/w32event.h>
43 #include <mono/utils/strenc.h>
44 #include <mono/utils/mono-counters.h>
45 #include <mono/utils/mono-error-internals.h>
46 #include <mono/utils/mono-memory-model.h>
47 #include <mono/utils/checked-build.h>
48 #include <mono/utils/mono-threads.h>
49 #include <mono/utils/mono-threads-coop.h>
50 #include "cominterop.h"
51 #include <mono/utils/w32api.h>
54 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error);
57 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error);
60 free_main_args (void);
63 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error);
66 array_full_copy_unchecked_size (MonoArray *src, MonoArray *dest, MonoClass *klass, uintptr_t size);
69 class_get_virtual_method (MonoClass *klass, MonoMethod *method, gboolean is_proxy, MonoError *error);
71 /* Class lazy loading functions */
72 static GENERATE_GET_CLASS_WITH_CACHE (pointer, "System.Reflection", "Pointer")
73 static GENERATE_GET_CLASS_WITH_CACHE (remoting_services, "System.Runtime.Remoting", "RemotingServices")
74 static GENERATE_GET_CLASS_WITH_CACHE (unhandled_exception_event_args, "System", "UnhandledExceptionEventArgs")
75 static GENERATE_GET_CLASS_WITH_CACHE (sta_thread_attribute, "System", "STAThreadAttribute")
76 static GENERATE_GET_CLASS_WITH_CACHE (activation_services, "System.Runtime.Remoting.Activation", "ActivationServices")
79 #define ldstr_lock() mono_os_mutex_lock (&ldstr_section)
80 #define ldstr_unlock() mono_os_mutex_unlock (&ldstr_section)
81 static mono_mutex_t ldstr_section;
85 * mono_runtime_object_init:
86 * \param this_obj the object to initialize
87 * This function calls the zero-argument constructor (which must
88 * exist) for the given object.
91 mono_runtime_object_init (MonoObject *this_obj)
94 mono_runtime_object_init_checked (this_obj, &error);
95 mono_error_assert_ok (&error);
99 * mono_runtime_object_init_checked:
100 * \param this_obj the object to initialize
101 * \param error set on error.
102 * This function calls the zero-argument constructor (which must
103 * exist) for the given object and returns TRUE on success, or FALSE
104 * on error and sets \p error.
107 mono_runtime_object_init_checked (MonoObject *this_obj, MonoError *error)
109 MONO_REQ_GC_UNSAFE_MODE;
111 MonoMethod *method = NULL;
112 MonoClass *klass = this_obj->vtable->klass;
115 method = mono_class_get_method_from_name (klass, ".ctor", 0);
117 g_error ("Could not lookup zero argument constructor for class %s", mono_type_get_full_name (klass));
119 if (method->klass->valuetype)
120 this_obj = (MonoObject *)mono_object_unbox (this_obj);
122 mono_runtime_invoke_checked (method, this_obj, NULL, error);
123 return is_ok (error);
126 /* The pseudo algorithm for type initialization from the spec
127 Note it doesn't say anything about domains - only threads.
129 2. If the type is initialized you are done.
130 2.1. If the type is not yet initialized, try to take an
132 2.2. If successful, record this thread as responsible for
133 initializing the type and proceed to step 2.3.
134 2.2.1. If not, see whether this thread or any thread
135 waiting for this thread to complete already holds the lock.
136 2.2.2. If so, return since blocking would create a deadlock. This thread
137 will now see an incompletely initialized state for the type,
138 but no deadlock will arise.
139 2.2.3 If not, block until the type is initialized then return.
140 2.3 Initialize the parent type and then all interfaces implemented
142 2.4 Execute the type initialization code for this type.
143 2.5 Mark the type as initialized, release the initialization lock,
144 awaken any threads waiting for this type to be initialized,
151 MonoNativeThreadId initializing_tid;
152 guint32 waiting_count;
155 /* condvar used to wait for 'done' becoming TRUE */
157 } TypeInitializationLock;
159 /* for locking access to type_initialization_hash and blocked_thread_hash */
160 static MonoCoopMutex type_initialization_section;
163 mono_type_initialization_lock (void)
165 /* The critical sections protected by this lock in mono_runtime_class_init_full () can block */
166 mono_coop_mutex_lock (&type_initialization_section);
170 mono_type_initialization_unlock (void)
172 mono_coop_mutex_unlock (&type_initialization_section);
176 mono_type_init_lock (TypeInitializationLock *lock)
178 MONO_REQ_GC_NEUTRAL_MODE;
180 mono_coop_mutex_lock (&lock->mutex);
184 mono_type_init_unlock (TypeInitializationLock *lock)
186 mono_coop_mutex_unlock (&lock->mutex);
189 /* from vtable to lock */
190 static GHashTable *type_initialization_hash;
192 /* from thread id to thread id being waited on */
193 static GHashTable *blocked_thread_hash;
196 static MonoThread *main_thread;
198 /* Functions supplied by the runtime */
199 static MonoRuntimeCallbacks callbacks;
202 * mono_thread_set_main:
203 * \param thread thread to set as the main thread
204 * This function can be used to instruct the runtime to treat \p thread
205 * as the main thread, ie, the thread that would normally execute the \c Main
206 * method. This basically means that at the end of \p thread, the runtime will
207 * wait for the existing foreground threads to quit and other such details.
210 mono_thread_set_main (MonoThread *thread)
212 MONO_REQ_GC_UNSAFE_MODE;
214 static gboolean registered = FALSE;
217 MONO_GC_REGISTER_ROOT_SINGLE (main_thread, MONO_ROOT_SOURCE_THREADING, "main thread object");
221 main_thread = thread;
225 * mono_thread_get_main:
228 mono_thread_get_main (void)
230 MONO_REQ_GC_UNSAFE_MODE;
236 mono_type_initialization_init (void)
238 mono_coop_mutex_init_recursive (&type_initialization_section);
239 type_initialization_hash = g_hash_table_new (NULL, NULL);
240 blocked_thread_hash = g_hash_table_new (NULL, NULL);
241 mono_os_mutex_init_recursive (&ldstr_section);
242 mono_register_jit_icall (ves_icall_string_alloc, "ves_icall_string_alloc", mono_create_icall_signature ("object int"), FALSE);
246 mono_type_initialization_cleanup (void)
249 /* This is causing race conditions with
250 * mono_release_type_locks
252 mono_coop_mutex_destroy (&type_initialization_section);
253 g_hash_table_destroy (type_initialization_hash);
254 type_initialization_hash = NULL;
256 mono_os_mutex_destroy (&ldstr_section);
257 g_hash_table_destroy (blocked_thread_hash);
258 blocked_thread_hash = NULL;
264 * get_type_init_exception_for_vtable:
266 * Return the stored type initialization exception for VTABLE.
268 static MonoException*
269 get_type_init_exception_for_vtable (MonoVTable *vtable)
271 MONO_REQ_GC_UNSAFE_MODE;
274 MonoDomain *domain = vtable->domain;
275 MonoClass *klass = vtable->klass;
279 if (!vtable->init_failed)
280 g_error ("Trying to get the init exception for a non-failed vtable of class %s", mono_type_get_full_name (klass));
283 * If the initializing thread was rudely aborted, the exception is not stored
287 mono_domain_lock (domain);
288 if (domain->type_init_exception_hash)
289 ex = (MonoException *)mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
290 mono_domain_unlock (domain);
293 if (klass->name_space && *klass->name_space)
294 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
296 full_name = g_strdup (klass->name);
297 ex = mono_get_exception_type_initialization_checked (full_name, NULL, &error);
299 return_val_if_nok (&error, NULL);
306 * mono_runtime_class_init:
307 * \param vtable vtable that needs to be initialized
308 * This routine calls the class constructor for \p 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 * \param vtable that neeeds to be initialized
341 * \param error set on error
342 * \returns TRUE if class constructor \c .cctor has been initialized successfully, or FALSE otherwise and sets \p error.
345 mono_runtime_class_init_full (MonoVTable *vtable, MonoError *error)
347 MONO_REQ_GC_UNSAFE_MODE;
349 MonoMethod *method = NULL;
352 MonoDomain *domain = vtable->domain;
353 TypeInitializationLock *lock;
354 MonoNativeThreadId tid;
355 int do_initialization = 0;
356 MonoDomain *last_domain = NULL;
357 gboolean pending_tae = FALSE;
361 if (vtable->initialized)
364 klass = vtable->klass;
366 if (!klass->image->checked_module_cctor) {
367 mono_image_check_for_module_cctor (klass->image);
368 if (klass->image->has_module_cctor) {
369 MonoClass *module_klass;
370 MonoVTable *module_vtable;
372 module_klass = mono_class_get_checked (klass->image, MONO_TOKEN_TYPE_DEF | 1, error);
377 module_vtable = mono_class_vtable_full (vtable->domain, module_klass, error);
380 if (!mono_runtime_class_init_full (module_vtable, error))
384 method = mono_class_get_cctor (klass);
386 vtable->initialized = 1;
390 tid = mono_native_thread_id_get ();
393 * Due some preprocessing inside a global lock. If we are the first thread
394 * trying to initialize this class, create a separate lock+cond var, and
395 * acquire it before leaving the global lock. The other threads will wait
399 mono_type_initialization_lock ();
400 /* double check... */
401 if (vtable->initialized) {
402 mono_type_initialization_unlock ();
405 if (vtable->init_failed) {
406 mono_type_initialization_unlock ();
408 /* The type initialization already failed once, rethrow the same exception */
409 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
412 lock = (TypeInitializationLock *)g_hash_table_lookup (type_initialization_hash, vtable);
414 /* This thread will get to do the initialization */
415 if (mono_domain_get () != domain) {
416 /* Transfer into the target domain */
417 last_domain = mono_domain_get ();
418 if (!mono_domain_set (domain, FALSE)) {
419 vtable->initialized = 1;
420 mono_type_initialization_unlock ();
421 mono_error_set_exception_instance (error, mono_get_exception_appdomain_unloaded ());
425 lock = (TypeInitializationLock *)g_malloc0 (sizeof (TypeInitializationLock));
426 mono_coop_mutex_init_recursive (&lock->mutex);
427 mono_coop_cond_init (&lock->cond);
428 lock->initializing_tid = tid;
429 lock->waiting_count = 1;
431 g_hash_table_insert (type_initialization_hash, vtable, lock);
432 do_initialization = 1;
435 TypeInitializationLock *pending_lock;
437 if (mono_native_thread_id_equals (lock->initializing_tid, tid)) {
438 mono_type_initialization_unlock ();
441 /* see if the thread doing the initialization is already blocked on this thread */
442 gboolean is_blocked = TRUE;
443 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (lock->initializing_tid));
444 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
445 if (mono_native_thread_id_equals (pending_lock->initializing_tid, tid)) {
446 if (!pending_lock->done) {
447 mono_type_initialization_unlock ();
450 /* the thread doing the initialization is blocked on this thread,
451 but on a lock that has already been freed. It just hasn't got
457 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (pending_lock->initializing_tid));
459 ++lock->waiting_count;
460 /* record the fact that we are waiting on the initializing thread */
462 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
464 mono_type_initialization_unlock ();
466 if (do_initialization) {
467 MonoException *exc = NULL;
469 /* We are holding the per-vtable lock, do the actual initialization */
471 mono_threads_begin_abort_protected_block ();
472 mono_runtime_try_invoke (method, NULL, NULL, (MonoObject**) &exc, error);
473 mono_threads_end_abort_protected_block ();
475 //exception extracted, error will be set to the right value later
476 if (exc == NULL && !mono_error_ok (error))//invoking failed but exc was not set
477 exc = mono_error_convert_to_exception (error);
479 mono_error_cleanup (error);
483 /* If the initialization failed, mark the class as unusable. */
484 /* Avoid infinite loops */
486 (klass->image == mono_defaults.corlib &&
487 !strcmp (klass->name_space, "System") &&
488 !strcmp (klass->name, "TypeInitializationException")))) {
489 vtable->init_failed = 1;
491 if (klass->name_space && *klass->name_space)
492 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
494 full_name = g_strdup (klass->name);
496 MonoException *exc_to_throw = mono_get_exception_type_initialization_checked (full_name, exc, error);
499 mono_error_assert_ok (error); //We can't recover from this, no way to fail a type we can't alloc a failure.
502 * Store the exception object so it could be thrown on subsequent
505 mono_domain_lock (domain);
506 if (!domain->type_init_exception_hash)
507 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");
508 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
509 mono_domain_unlock (domain);
513 mono_domain_set (last_domain, TRUE);
515 /* Signal to the other threads that we are done */
516 mono_type_init_lock (lock);
518 mono_coop_cond_broadcast (&lock->cond);
519 mono_type_init_unlock (lock);
522 * This can happen if the cctor self-aborts. We need to reactivate tae
523 * (next interruption checkpoint will throw it) and make sure we won't
524 * throw tie for the type.
526 if (exc && mono_object_class (exc) == mono_defaults.threadabortexception_class) {
528 mono_thread_resume_interruption (FALSE);
531 /* this just blocks until the initializing thread is done */
532 mono_type_init_lock (lock);
534 mono_coop_cond_wait (&lock->cond, &lock->mutex);
535 mono_type_init_unlock (lock);
538 /* Do cleanup and setting vtable->initialized inside the global lock again */
539 mono_type_initialization_lock ();
540 if (!do_initialization)
541 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
542 gboolean deleted = unref_type_lock (lock);
544 g_hash_table_remove (type_initialization_hash, vtable);
545 /* Have to set this here since we check it inside the global lock */
546 if (do_initialization && !vtable->init_failed)
547 vtable->initialized = 1;
548 mono_type_initialization_unlock ();
550 /* If vtable init fails because of TAE, we don't throw TIE, only the TAE */
551 if (vtable->init_failed && !pending_tae) {
552 /* Either we were the initializing thread or we waited for the initialization */
553 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
560 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
562 MONO_REQ_GC_NEUTRAL_MODE;
564 MonoVTable *vtable = (MonoVTable*)key;
566 TypeInitializationLock *lock = (TypeInitializationLock*) value;
567 if (mono_native_thread_id_equals (lock->initializing_tid, MONO_UINT_TO_NATIVE_THREAD_ID (GPOINTER_TO_UINT (user))) && !lock->done) {
570 * Have to set this since it cannot be set by the normal code in
571 * mono_runtime_class_init (). In this case, the exception object is not stored,
572 * and get_type_init_exception_for_class () needs to be aware of this.
574 mono_type_init_lock (lock);
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 * \param method The method to compile.
641 * This JIT-compiles the method, and returns the pointer to the native code
645 mono_compile_method (MonoMethod *method)
648 gpointer result = mono_compile_method_checked (method, &error);
649 mono_error_cleanup (&error);
654 * mono_compile_method_checked:
655 * \param method The method to compile.
656 * \param error set on error.
657 * This JIT-compiles the method, and returns the pointer to the native code
658 * produced. On failure returns NULL and sets \p error.
661 mono_compile_method_checked (MonoMethod *method, MonoError *error)
665 MONO_REQ_GC_NEUTRAL_MODE
669 g_assert (callbacks.compile_method);
670 res = callbacks.compile_method (method, error);
675 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper, MonoError *error)
679 MONO_REQ_GC_NEUTRAL_MODE;
682 res = callbacks.create_jump_trampoline (domain, method, add_sync_wrapper, error);
687 mono_runtime_create_delegate_trampoline (MonoClass *klass)
689 MONO_REQ_GC_NEUTRAL_MODE
691 g_assert (callbacks.create_delegate_trampoline);
692 return callbacks.create_delegate_trampoline (mono_domain_get (), klass);
696 * mono_runtime_free_method:
697 * \param domain domain where the method is hosted
698 * \param method method to release
699 * This routine is invoked to free the resources associated with
700 * a method that has been JIT compiled. This is used to discard
701 * methods that were used only temporarily (for example, used in marshalling)
704 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
706 MONO_REQ_GC_NEUTRAL_MODE
708 if (callbacks.free_method)
709 callbacks.free_method (domain, method);
711 mono_method_clear_object (domain, method);
713 mono_free_method (method);
717 * The vtables in the root appdomain are assumed to be reachable by other
718 * roots, and we don't use typed allocation in the other domains.
721 /* The sync block is no longer a GC pointer */
722 #define GC_HEADER_BITMAP (0)
724 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
727 compute_class_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
729 MONO_REQ_GC_NEUTRAL_MODE;
731 MonoClassField *field;
737 max_size = mono_class_data_size (klass) / sizeof (gpointer);
739 max_size = klass->instance_size / sizeof (gpointer);
740 if (max_size > size) {
741 g_assert (offset <= 0);
742 bitmap = (gsize *)g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
746 /* An Ephemeron cannot be marked by sgen */
747 if (mono_gc_is_moving () && !static_fields && klass->image == mono_defaults.corlib && !strcmp ("Ephemeron", klass->name)) {
749 memset (bitmap, 0, size / 8);
753 for (p = klass; p != NULL; p = p->parent) {
754 gpointer iter = NULL;
755 while ((field = mono_class_get_fields (p, &iter))) {
759 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
761 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
764 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
767 /* FIXME: should not happen, flag as type load error */
768 if (field->type->byref)
771 if (static_fields && field->offset == -1)
775 pos = field->offset / sizeof (gpointer);
778 type = mono_type_get_underlying_type (field->type);
779 switch (type->type) {
783 case MONO_TYPE_FNPTR:
785 case MONO_TYPE_STRING:
786 case MONO_TYPE_SZARRAY:
787 case MONO_TYPE_CLASS:
788 case MONO_TYPE_OBJECT:
789 case MONO_TYPE_ARRAY:
790 g_assert ((field->offset % sizeof(gpointer)) == 0);
792 g_assert (pos < size || pos <= max_size);
793 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
794 *max_set = MAX (*max_set, pos);
796 case MONO_TYPE_GENERICINST:
797 if (!mono_type_generic_inst_is_valuetype (type)) {
798 g_assert ((field->offset % sizeof(gpointer)) == 0);
800 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
801 *max_set = MAX (*max_set, pos);
806 case MONO_TYPE_VALUETYPE: {
807 MonoClass *fclass = mono_class_from_mono_type (field->type);
808 if (fclass->has_references) {
809 /* remove the object header */
810 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
824 case MONO_TYPE_BOOLEAN:
828 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
839 * mono_class_compute_bitmap:
841 * Mono internal function to compute a bitmap of reference fields in a class.
844 mono_class_compute_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
846 MONO_REQ_GC_NEUTRAL_MODE;
848 return compute_class_bitmap (klass, bitmap, size, offset, max_set, static_fields);
853 * similar to the above, but sets the bits in the bitmap for any non-ref field
854 * and ignores static fields
857 compute_class_non_ref_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset)
859 MonoClassField *field;
864 max_size = class->instance_size / sizeof (gpointer);
865 if (max_size >= size) {
866 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
869 for (p = class; p != NULL; p = p->parent) {
870 gpointer iter = NULL;
871 while ((field = mono_class_get_fields (p, &iter))) {
874 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
876 /* FIXME: should not happen, flag as type load error */
877 if (field->type->byref)
880 pos = field->offset / sizeof (gpointer);
883 type = mono_type_get_underlying_type (field->type);
884 switch (type->type) {
885 #if SIZEOF_VOID_P == 8
889 case MONO_TYPE_FNPTR:
894 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
895 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
896 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
899 #if SIZEOF_VOID_P == 4
903 case MONO_TYPE_FNPTR:
908 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
909 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
910 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
916 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
917 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
918 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
921 case MONO_TYPE_BOOLEAN:
924 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
926 case MONO_TYPE_STRING:
927 case MONO_TYPE_SZARRAY:
928 case MONO_TYPE_CLASS:
929 case MONO_TYPE_OBJECT:
930 case MONO_TYPE_ARRAY:
932 case MONO_TYPE_GENERICINST:
933 if (!mono_type_generic_inst_is_valuetype (type)) {
938 case MONO_TYPE_VALUETYPE: {
939 MonoClass *fclass = mono_class_from_mono_type (field->type);
940 /* remove the object header */
941 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
945 g_assert_not_reached ();
954 * mono_class_insecure_overlapping:
955 * check if a class with explicit layout has references and non-references
956 * fields overlapping.
958 * Returns: TRUE if it is insecure to load the type.
961 mono_class_insecure_overlapping (MonoClass *klass)
965 gsize default_bitmap [4] = {0};
967 gsize default_nrbitmap [4] = {0};
968 int i, insecure = FALSE;
971 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
972 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
974 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
975 int idx = i % (sizeof (bitmap [0]) * 8);
976 if (bitmap [idx] & nrbitmap [idx]) {
981 if (bitmap != default_bitmap)
983 if (nrbitmap != default_nrbitmap)
986 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
994 ves_icall_string_alloc (int length)
997 MonoString *str = mono_string_new_size_checked (mono_domain_get (), length, &error);
998 mono_error_set_pending_exception (&error);
1003 /* LOCKING: Acquires the loader lock */
1005 mono_class_compute_gc_descriptor (MonoClass *klass)
1007 MONO_REQ_GC_NEUTRAL_MODE;
1011 gsize default_bitmap [4] = {0};
1012 MonoGCDescriptor gc_descr;
1015 mono_class_init (klass);
1017 if (klass->gc_descr_inited)
1020 bitmap = default_bitmap;
1021 if (klass == mono_defaults.string_class) {
1022 gc_descr = mono_gc_make_descr_for_string (bitmap, 2);
1023 } else if (klass->rank) {
1024 mono_class_compute_gc_descriptor (klass->element_class);
1025 if (MONO_TYPE_IS_REFERENCE (&klass->element_class->byval_arg)) {
1027 gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
1028 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1029 class->name_space, class->name);*/
1031 /* remove the object header */
1032 bitmap = compute_class_bitmap (klass->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
1033 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));
1034 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1035 class->name_space, class->name);*/
1036 if (bitmap != default_bitmap)
1040 /*static int count = 0;
1043 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1044 gc_descr = mono_gc_make_descr_for_object (bitmap, max_set + 1, klass->instance_size);
1046 if (class->gc_descr == MONO_GC_DESCRIPTOR_NULL)
1047 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
1049 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
1050 if (bitmap != default_bitmap)
1054 /* Publish the data */
1055 mono_loader_lock ();
1056 klass->gc_descr = gc_descr;
1057 mono_memory_barrier ();
1058 klass->gc_descr_inited = TRUE;
1059 mono_loader_unlock ();
1063 * field_is_special_static:
1064 * @fklass: The MonoClass to look up.
1065 * @field: The MonoClassField describing the field.
1067 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1068 * SPECIAL_STATIC_NONE otherwise.
1071 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1073 MONO_REQ_GC_NEUTRAL_MODE;
1076 MonoCustomAttrInfo *ainfo;
1078 ainfo = mono_custom_attrs_from_field_checked (fklass, field, &error);
1079 mono_error_cleanup (&error); /* FIXME don't swallow the error? */
1082 for (i = 0; i < ainfo->num_attrs; ++i) {
1083 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1084 if (klass->image == mono_defaults.corlib) {
1085 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1086 mono_custom_attrs_free (ainfo);
1087 return SPECIAL_STATIC_THREAD;
1089 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1090 mono_custom_attrs_free (ainfo);
1091 return SPECIAL_STATIC_CONTEXT;
1095 mono_custom_attrs_free (ainfo);
1096 return SPECIAL_STATIC_NONE;
1099 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1100 #define mix(a,b,c) { \
1101 a -= c; a ^= rot(c, 4); c += b; \
1102 b -= a; b ^= rot(a, 6); a += c; \
1103 c -= b; c ^= rot(b, 8); b += a; \
1104 a -= c; a ^= rot(c,16); c += b; \
1105 b -= a; b ^= rot(a,19); a += c; \
1106 c -= b; c ^= rot(b, 4); b += a; \
1108 #define final(a,b,c) { \
1109 c ^= b; c -= rot(b,14); \
1110 a ^= c; a -= rot(c,11); \
1111 b ^= a; b -= rot(a,25); \
1112 c ^= b; c -= rot(b,16); \
1113 a ^= c; a -= rot(c,4); \
1114 b ^= a; b -= rot(a,14); \
1115 c ^= b; c -= rot(b,24); \
1119 * mono_method_get_imt_slot:
1121 * The IMT slot is embedded into AOTed code, so this must return the same value
1122 * for the same method across all executions. This means:
1123 * - pointers shouldn't be used as hash values.
1124 * - mono_metadata_str_hash () should be used for hashing strings.
1127 mono_method_get_imt_slot (MonoMethod *method)
1129 MONO_REQ_GC_NEUTRAL_MODE;
1131 MonoMethodSignature *sig;
1133 guint32 *hashes_start, *hashes;
1137 /* This can be used to stress tests the collision code */
1141 * We do this to simplify generic sharing. It will hurt
1142 * performance in cases where a class implements two different
1143 * instantiations of the same generic interface.
1144 * The code in build_imt_slots () depends on this.
1146 if (method->is_inflated)
1147 method = ((MonoMethodInflated*)method)->declaring;
1149 sig = mono_method_signature (method);
1150 hashes_count = sig->param_count + 4;
1151 hashes_start = (guint32 *)malloc (hashes_count * sizeof (guint32));
1152 hashes = hashes_start;
1154 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1155 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1156 method->klass->name_space, method->klass->name, method->name);
1159 /* Initialize hashes */
1160 hashes [0] = mono_metadata_str_hash (method->klass->name);
1161 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1162 hashes [2] = mono_metadata_str_hash (method->name);
1163 hashes [3] = mono_metadata_type_hash (sig->ret);
1164 for (i = 0; i < sig->param_count; i++) {
1165 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1168 /* Setup internal state */
1169 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1171 /* Handle most of the hashes */
1172 while (hashes_count > 3) {
1181 /* Handle the last 3 hashes (all the case statements fall through) */
1182 switch (hashes_count) {
1183 case 3 : c += hashes [2];
1184 case 2 : b += hashes [1];
1185 case 1 : a += hashes [0];
1187 case 0: /* nothing left to add */
1191 g_free (hashes_start);
1192 /* Report the result */
1193 return c % MONO_IMT_SIZE;
1202 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1203 MONO_REQ_GC_NEUTRAL_MODE;
1205 guint32 imt_slot = mono_method_get_imt_slot (method);
1206 MonoImtBuilderEntry *entry;
1208 if (slot_num >= 0 && imt_slot != slot_num) {
1209 /* we build just a single imt slot and this is not it */
1213 entry = (MonoImtBuilderEntry *)g_malloc0 (sizeof (MonoImtBuilderEntry));
1214 entry->key = method;
1215 entry->value.vtable_slot = vtable_slot;
1216 entry->next = imt_builder [imt_slot];
1217 if (imt_builder [imt_slot] != NULL) {
1218 entry->children = imt_builder [imt_slot]->children + 1;
1219 if (entry->children == 1) {
1220 mono_stats.imt_slots_with_collisions++;
1221 *imt_collisions_bitmap |= (1 << imt_slot);
1224 entry->children = 0;
1225 mono_stats.imt_used_slots++;
1227 imt_builder [imt_slot] = entry;
1230 char *method_name = mono_method_full_name (method, TRUE);
1231 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1232 method, method_name, imt_slot, vtable_slot, entry->children);
1233 g_free (method_name);
1240 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1242 MonoMethod *method = e->key;
1243 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1247 method->klass->name_space,
1248 method->klass->name,
1251 printf (" * %s: NULL\n", message);
1257 compare_imt_builder_entries (const void *p1, const void *p2) {
1258 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1259 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1261 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1265 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1267 MONO_REQ_GC_NEUTRAL_MODE;
1269 int count = end - start;
1270 int chunk_start = out_array->len;
1273 for (i = start; i < end; ++i) {
1274 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1275 item->key = sorted_array [i]->key;
1276 item->value = sorted_array [i]->value;
1277 item->has_target_code = sorted_array [i]->has_target_code;
1278 item->is_equals = TRUE;
1280 item->check_target_idx = out_array->len + 1;
1282 item->check_target_idx = 0;
1283 g_ptr_array_add (out_array, item);
1286 int middle = start + count / 2;
1287 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1289 item->key = sorted_array [middle]->key;
1290 item->is_equals = FALSE;
1291 g_ptr_array_add (out_array, item);
1292 imt_emit_ir (sorted_array, start, middle, out_array);
1293 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1299 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1300 MONO_REQ_GC_NEUTRAL_MODE;
1302 int number_of_entries = entries->children + 1;
1303 MonoImtBuilderEntry **sorted_array = (MonoImtBuilderEntry **)malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1304 GPtrArray *result = g_ptr_array_new ();
1305 MonoImtBuilderEntry *current_entry;
1308 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1309 sorted_array [i] = current_entry;
1311 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1313 /*for (i = 0; i < number_of_entries; i++) {
1314 print_imt_entry (" sorted array:", sorted_array [i], i);
1317 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1319 g_free (sorted_array);
1324 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1326 MONO_REQ_GC_NEUTRAL_MODE;
1328 if (imt_builder_entry != NULL) {
1329 if (imt_builder_entry->children == 0 && !fail_tramp && !always_build_imt_trampolines) {
1330 /* No collision, return the vtable slot contents */
1331 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1333 /* Collision, build the trampoline */
1334 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1337 result = imt_trampoline_builder (vtable, domain,
1338 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1339 for (i = 0; i < imt_ir->len; ++i)
1340 g_free (g_ptr_array_index (imt_ir, i));
1341 g_ptr_array_free (imt_ir, TRUE);
1353 static MonoImtBuilderEntry*
1354 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1357 * LOCKING: requires the loader and domain locks.
1361 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1363 MONO_REQ_GC_NEUTRAL_MODE;
1367 guint32 imt_collisions_bitmap = 0;
1368 MonoImtBuilderEntry **imt_builder = (MonoImtBuilderEntry **)calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1369 int method_count = 0;
1370 gboolean record_method_count_for_max_collisions = FALSE;
1371 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1374 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1376 for (i = 0; i < klass->interface_offsets_count; ++i) {
1377 MonoClass *iface = klass->interfaces_packed [i];
1378 int interface_offset = klass->interface_offsets_packed [i];
1379 int method_slot_in_interface, vt_slot;
1381 if (mono_class_has_variant_generic_params (iface))
1382 has_variant_iface = TRUE;
1384 mono_class_setup_methods (iface);
1385 vt_slot = interface_offset;
1386 int mcount = mono_class_get_method_count (iface);
1387 for (method_slot_in_interface = 0; method_slot_in_interface < mcount; method_slot_in_interface++) {
1390 if (slot_num >= 0 && mono_class_is_ginst (iface)) {
1392 * The imt slot of the method is the same as for its declaring method,
1393 * see the comment in mono_method_get_imt_slot (), so we can
1394 * avoid inflating methods which will be discarded by
1395 * add_imt_builder_entry anyway.
1397 method = mono_class_get_method_by_index (mono_class_get_generic_class (iface)->container_class, method_slot_in_interface);
1398 if (mono_method_get_imt_slot (method) != slot_num) {
1403 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1404 if (method->is_generic) {
1405 has_generic_virtual = TRUE;
1410 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1411 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1416 if (extra_interfaces) {
1417 int interface_offset = klass->vtable_size;
1419 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1420 MonoClass* iface = (MonoClass *)list_item->data;
1421 int method_slot_in_interface;
1422 int mcount = mono_class_get_method_count (iface);
1423 for (method_slot_in_interface = 0; method_slot_in_interface < mcount; method_slot_in_interface++) {
1424 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1426 if (method->is_generic)
1427 has_generic_virtual = TRUE;
1428 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1430 interface_offset += mcount;
1433 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1434 /* overwrite the imt slot only if we're building all the entries or if
1435 * we're building this specific one
1437 if (slot_num < 0 || i == slot_num) {
1438 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1441 if (imt_builder [i]) {
1442 MonoImtBuilderEntry *entry;
1444 /* Link entries with imt_builder [i] */
1445 for (entry = entries; entry->next; entry = entry->next) {
1447 MonoMethod *method = (MonoMethod*)entry->key;
1448 char *method_name = mono_method_full_name (method, TRUE);
1449 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1450 g_free (method_name);
1453 entry->next = imt_builder [i];
1454 entries->children += imt_builder [i]->children + 1;
1456 imt_builder [i] = entries;
1459 if (has_generic_virtual || has_variant_iface) {
1461 * There might be collisions later when the the trampoline is expanded.
1463 imt_collisions_bitmap |= (1 << i);
1466 * The IMT trampoline might be called with an instance of one of the
1467 * generic virtual methods, so has to fallback to the IMT trampoline.
1469 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline (vt, i));
1471 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1474 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1478 if (imt_builder [i] != NULL) {
1479 int methods_in_slot = imt_builder [i]->children + 1;
1480 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1481 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1482 record_method_count_for_max_collisions = TRUE;
1484 method_count += methods_in_slot;
1488 mono_stats.imt_number_of_methods += method_count;
1489 if (record_method_count_for_max_collisions) {
1490 mono_stats.imt_method_count_when_max_collisions = method_count;
1493 for (i = 0; i < MONO_IMT_SIZE; i++) {
1494 MonoImtBuilderEntry* entry = imt_builder [i];
1495 while (entry != NULL) {
1496 MonoImtBuilderEntry* next = entry->next;
1501 g_free (imt_builder);
1502 /* we OR the bitmap since we may build just a single imt slot at a time */
1503 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1507 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1508 MONO_REQ_GC_NEUTRAL_MODE;
1510 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1514 * mono_vtable_build_imt_slot:
1515 * \param vtable virtual object table struct
1516 * \param imt_slot slot in the IMT table
1517 * Fill the given \p imt_slot in the IMT table of \p vtable with
1518 * a trampoline or a trampoline for the case of collisions.
1519 * This is part of the internal mono API.
1520 * LOCKING: Take the domain lock.
1523 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1525 MONO_REQ_GC_NEUTRAL_MODE;
1527 gpointer *imt = (gpointer*)vtable;
1528 imt -= MONO_IMT_SIZE;
1529 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1531 /* no support for extra interfaces: the proxy objects will need
1532 * to build the complete IMT
1533 * Update and heck needs to ahppen inside the proper domain lock, as all
1534 * the changes made to a MonoVTable.
1536 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1537 mono_domain_lock (vtable->domain);
1538 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1539 if (!callbacks.imt_entry_inited (vtable, imt_slot))
1540 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1541 mono_domain_unlock (vtable->domain);
1542 mono_loader_unlock ();
1545 #define THUNK_THRESHOLD 10
1548 * mono_method_alloc_generic_virtual_trampoline:
1549 * \param domain a domain
1550 * \param size size in bytes
1551 * Allocs \p size bytes to be used for the code of a generic virtual
1552 * trampoline. It's either allocated from the domain's code manager or
1553 * reused from a previously invalidated piece.
1554 * LOCKING: The domain lock must be held.
1557 mono_method_alloc_generic_virtual_trampoline (MonoDomain *domain, int size)
1559 MONO_REQ_GC_NEUTRAL_MODE;
1561 static gboolean inited = FALSE;
1562 static int generic_virtual_trampolines_size = 0;
1565 mono_counters_register ("Generic virtual trampoline bytes",
1566 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_trampolines_size);
1569 generic_virtual_trampolines_size += size;
1571 return mono_domain_code_reserve (domain, size);
1574 typedef struct _GenericVirtualCase {
1578 struct _GenericVirtualCase *next;
1579 } GenericVirtualCase;
1582 * get_generic_virtual_entries:
1584 * Return IMT entries for the generic virtual method instances and
1585 * variant interface methods for vtable slot
1588 static MonoImtBuilderEntry*
1589 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1591 MONO_REQ_GC_NEUTRAL_MODE;
1593 GenericVirtualCase *list;
1594 MonoImtBuilderEntry *entries;
1596 mono_domain_lock (domain);
1597 if (!domain->generic_virtual_cases)
1598 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1600 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1603 for (; list; list = list->next) {
1604 MonoImtBuilderEntry *entry;
1606 if (list->count < THUNK_THRESHOLD)
1609 entry = g_new0 (MonoImtBuilderEntry, 1);
1610 entry->key = list->method;
1611 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1612 entry->has_target_code = 1;
1614 entry->children = entries->children + 1;
1615 entry->next = entries;
1619 mono_domain_unlock (domain);
1621 /* FIXME: Leaking memory ? */
1626 * \param domain a domain
1627 * \param vtable_slot pointer to the vtable slot
1628 * \param method the inflated generic virtual method
1629 * \param code the method's code
1631 * Registers a call via unmanaged code to a generic virtual method
1632 * instantiation or variant interface method. If the number of calls reaches a threshold
1633 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1634 * virtual method trampoline.
1637 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1638 gpointer *vtable_slot,
1639 MonoMethod *method, gpointer code)
1641 MONO_REQ_GC_NEUTRAL_MODE;
1643 static gboolean inited = FALSE;
1644 static int num_added = 0;
1645 static int num_freed = 0;
1647 GenericVirtualCase *gvc, *list;
1648 MonoImtBuilderEntry *entries;
1652 mono_domain_lock (domain);
1653 if (!domain->generic_virtual_cases)
1654 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1657 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1658 mono_counters_register ("Freed IMT trampolines", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_freed);
1662 /* Check whether the case was already added */
1663 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1666 if (gvc->method == method)
1671 /* If not found, make a new one */
1673 gvc = (GenericVirtualCase *)mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1674 gvc->method = method;
1677 gvc->next = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1679 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1684 if (++gvc->count == THUNK_THRESHOLD) {
1685 gpointer *old_thunk = (void **)*vtable_slot;
1686 gpointer vtable_trampoline = NULL;
1687 gpointer imt_trampoline = NULL;
1689 if ((gpointer)vtable_slot < (gpointer)vtable) {
1690 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1691 int imt_slot = MONO_IMT_SIZE + displacement;
1693 /* Force the rebuild of the trampoline at the next call */
1694 imt_trampoline = callbacks.get_imt_trampoline (vtable, imt_slot);
1695 *vtable_slot = imt_trampoline;
1697 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline (vtable, (gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1699 entries = get_generic_virtual_entries (domain, vtable_slot);
1701 sorted = imt_sort_slot_entries (entries);
1703 *vtable_slot = imt_trampoline_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1707 MonoImtBuilderEntry *next = entries->next;
1712 for (i = 0; i < sorted->len; ++i)
1713 g_free (g_ptr_array_index (sorted, i));
1714 g_ptr_array_free (sorted, TRUE);
1716 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1721 mono_domain_unlock (domain);
1724 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error);
1727 * mono_class_vtable:
1728 * \param domain the application domain
1729 * \param class the class to initialize
1730 * VTables are domain specific because we create domain specific code, and
1731 * they contain the domain specific static class data.
1732 * On failure, NULL is returned, and \c class->exception_type is set.
1735 mono_class_vtable (MonoDomain *domain, MonoClass *klass)
1738 MonoVTable* vtable = mono_class_vtable_full (domain, klass, &error);
1739 mono_error_cleanup (&error);
1744 * mono_class_vtable_full:
1745 * \param domain the application domain
1746 * \param class the class to initialize
1747 * \param error set on failure.
1748 * VTables are domain specific because we create domain specific code, and
1749 * they contain the domain specific static class data.
1752 mono_class_vtable_full (MonoDomain *domain, MonoClass *klass, MonoError *error)
1754 MONO_REQ_GC_UNSAFE_MODE;
1756 MonoClassRuntimeInfo *runtime_info;
1762 if (mono_class_has_failure (klass)) {
1763 mono_error_set_for_class_failure (error, klass);
1767 /* this check can be inlined in jitted code, too */
1768 runtime_info = klass->runtime_info;
1769 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1770 return runtime_info->domain_vtables [domain->domain_id];
1771 return mono_class_create_runtime_vtable (domain, klass, error);
1775 * mono_class_try_get_vtable:
1776 * \param domain the application domain
1777 * \param class the class to initialize
1778 * This function tries to get the associated vtable from \p class if
1779 * it was already created.
1782 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *klass)
1784 MONO_REQ_GC_NEUTRAL_MODE;
1786 MonoClassRuntimeInfo *runtime_info;
1790 runtime_info = klass->runtime_info;
1791 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1792 return runtime_info->domain_vtables [domain->domain_id];
1797 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1799 MONO_REQ_GC_NEUTRAL_MODE;
1801 size_t alloc_offset;
1804 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1805 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1806 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1808 if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1809 g_assert ((imt_table_bytes & 7) == 4);
1816 return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1820 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error)
1822 MONO_REQ_GC_UNSAFE_MODE;
1825 MonoClassRuntimeInfo *runtime_info, *old_info;
1826 MonoClassField *field;
1828 int i, vtable_slots;
1829 size_t imt_table_bytes;
1831 guint32 vtable_size, class_size;
1833 gpointer *interface_offsets;
1837 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1838 mono_domain_lock (domain);
1839 runtime_info = klass->runtime_info;
1840 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1841 mono_domain_unlock (domain);
1842 mono_loader_unlock ();
1843 return runtime_info->domain_vtables [domain->domain_id];
1845 if (!klass->inited || mono_class_has_failure (klass)) {
1846 if (!mono_class_init (klass) || mono_class_has_failure (klass)) {
1847 mono_domain_unlock (domain);
1848 mono_loader_unlock ();
1849 mono_error_set_for_class_failure (error, klass);
1854 /* Array types require that their element type be valid*/
1855 if (klass->byval_arg.type == MONO_TYPE_ARRAY || klass->byval_arg.type == MONO_TYPE_SZARRAY) {
1856 MonoClass *element_class = klass->element_class;
1857 if (!element_class->inited)
1858 mono_class_init (element_class);
1860 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1861 if (!mono_class_has_failure (element_class) && !element_class->vtable_size)
1862 mono_class_setup_vtable (element_class);
1864 if (mono_class_has_failure (element_class)) {
1865 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1866 if (!mono_class_has_failure (klass))
1867 mono_class_set_type_load_failure (klass, "");
1868 mono_domain_unlock (domain);
1869 mono_loader_unlock ();
1870 mono_error_set_for_class_failure (error, klass);
1876 * For some classes, mono_class_init () already computed klass->vtable_size, and
1877 * that is all that is needed because of the vtable trampolines.
1879 if (!klass->vtable_size)
1880 mono_class_setup_vtable (klass);
1882 if (mono_class_is_ginst (klass) && !klass->vtable)
1883 mono_class_check_vtable_constraints (klass, NULL);
1885 /* Initialize klass->has_finalize */
1886 mono_class_has_finalizer (klass);
1888 if (mono_class_has_failure (klass)) {
1889 mono_domain_unlock (domain);
1890 mono_loader_unlock ();
1891 mono_error_set_for_class_failure (error, klass);
1895 vtable_slots = klass->vtable_size;
1896 /* we add an additional vtable slot to store the pointer to static field data only when needed */
1897 class_size = mono_class_data_size (klass);
1901 if (klass->interface_offsets_count) {
1902 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1903 mono_stats.imt_number_of_tables++;
1904 mono_stats.imt_tables_size += imt_table_bytes;
1906 imt_table_bytes = 0;
1909 vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
1911 mono_stats.used_class_count++;
1912 mono_stats.class_vtable_size += vtable_size;
1914 interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
1915 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1916 g_assert (!((gsize)vt & 7));
1919 vt->rank = klass->rank;
1920 vt->domain = domain;
1922 mono_class_compute_gc_descriptor (klass);
1925 * We can't use typed allocation in the non-root domains, since the
1926 * collector needs the GC descriptor stored in the vtable even after
1927 * the mempool containing the vtable is destroyed when the domain is
1928 * unloaded. An alternative might be to allocate vtables in the GC
1929 * heap, but this does not seem to work (it leads to crashes inside
1930 * libgc). If that approach is tried, two gc descriptors need to be
1931 * allocated for each class: one for the root domain, and one for all
1932 * other domains. The second descriptor should contain a bit for the
1933 * vtable field in MonoObject, since we can no longer assume the
1934 * vtable is reachable by other roots after the appdomain is unloaded.
1936 if (!mono_gc_is_moving () && domain != mono_get_root_domain () && !mono_dont_free_domains)
1937 vt->gc_descr = MONO_GC_DESCRIPTOR_NULL;
1939 vt->gc_descr = klass->gc_descr;
1941 gc_bits = mono_gc_get_vtable_bits (klass);
1942 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
1944 vt->gc_bits = gc_bits;
1947 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
1948 if (klass->has_static_refs) {
1949 MonoGCDescriptor statics_gc_descr;
1951 gsize default_bitmap [4] = {0};
1954 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1955 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], klass->name_space, klass->name, class_size);*/
1956 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1957 vt->vtable [klass->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr, MONO_ROOT_SOURCE_STATIC, "managed static variables");
1958 if (bitmap != default_bitmap)
1961 vt->vtable [klass->vtable_size] = mono_domain_alloc0 (domain, class_size);
1963 vt->has_static_fields = TRUE;
1964 mono_stats.class_static_data_size += class_size;
1968 while ((field = mono_class_get_fields (klass, &iter))) {
1969 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1971 if (mono_field_is_deleted (field))
1973 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1974 gint32 special_static = klass->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (klass, field);
1975 if (special_static != SPECIAL_STATIC_NONE) {
1976 guint32 size, offset;
1978 gsize default_bitmap [4] = {0};
1983 if (mono_type_is_reference (field->type)) {
1984 default_bitmap [0] = 1;
1986 bitmap = default_bitmap;
1987 } else if (mono_type_is_struct (field->type)) {
1988 fclass = mono_class_from_mono_type (field->type);
1989 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
1990 numbits = max_set + 1;
1992 default_bitmap [0] = 0;
1994 bitmap = default_bitmap;
1996 size = mono_type_size (field->type, &align);
1997 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
1998 if (!domain->special_static_fields)
1999 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2000 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2001 if (bitmap != default_bitmap)
2004 * This marks the field as special static to speed up the
2005 * checks in mono_field_static_get/set_value ().
2011 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2012 MonoClass *fklass = mono_class_from_mono_type (field->type);
2013 const char *data = mono_field_get_data (field);
2015 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2016 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2017 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2020 if (fklass->valuetype) {
2021 memcpy (t, data, mono_class_value_size (fklass, NULL));
2023 /* it's a pointer type: add check */
2024 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2031 vt->max_interface_id = klass->max_interface_id;
2032 vt->interface_bitmap = klass->interface_bitmap;
2034 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2035 // class->name, klass->interface_offsets_count);
2037 /* Initialize vtable */
2038 if (callbacks.get_vtable_trampoline) {
2039 // This also covers the AOT case
2040 for (i = 0; i < klass->vtable_size; ++i) {
2041 vt->vtable [i] = callbacks.get_vtable_trampoline (vt, i);
2044 mono_class_setup_vtable (klass);
2046 for (i = 0; i < klass->vtable_size; ++i) {
2049 cm = klass->vtable [i];
2051 vt->vtable [i] = callbacks.create_jit_trampoline (domain, cm, error);
2052 if (!is_ok (error)) {
2053 mono_domain_unlock (domain);
2054 mono_loader_unlock ();
2061 if (imt_table_bytes) {
2062 /* Now that the vtable is full, we can actually fill up the IMT */
2063 for (i = 0; i < MONO_IMT_SIZE; ++i)
2064 interface_offsets [i] = callbacks.get_imt_trampoline (vt, i);
2068 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2069 * re-acquire them and check if another thread has created the vtable in the meantime.
2071 /* Special case System.MonoType to avoid infinite recursion */
2072 if (klass != mono_defaults.runtimetype_class) {
2073 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2074 if (!is_ok (error)) {
2075 mono_domain_unlock (domain);
2076 mono_loader_unlock ();
2080 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2081 /* This is unregistered in
2082 unregister_vtable_reflection_type() in
2084 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2087 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (klass));
2089 /* class_vtable_array keeps an array of created vtables
2091 g_ptr_array_add (domain->class_vtable_array, vt);
2092 /* klass->runtime_info is protected by the loader lock, both when
2093 * it it enlarged and when it is stored info.
2097 * Store the vtable in klass->runtime_info.
2098 * klass->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2100 mono_memory_barrier ();
2102 old_info = klass->runtime_info;
2103 if (old_info && old_info->max_domain >= domain->domain_id) {
2104 /* someone already created a large enough runtime info */
2105 old_info->domain_vtables [domain->domain_id] = vt;
2107 int new_size = domain->domain_id;
2109 new_size = MAX (new_size, old_info->max_domain);
2111 /* make the new size a power of two */
2113 while (new_size > i)
2116 /* this is a bounded memory retention issue: may want to
2117 * handle it differently when we'll have a rcu-like system.
2119 runtime_info = (MonoClassRuntimeInfo *)mono_image_alloc0 (klass->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2120 runtime_info->max_domain = new_size - 1;
2121 /* copy the stuff from the older info */
2123 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2125 runtime_info->domain_vtables [domain->domain_id] = vt;
2127 mono_memory_barrier ();
2128 klass->runtime_info = runtime_info;
2131 if (klass == mono_defaults.runtimetype_class) {
2132 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2133 if (!is_ok (error)) {
2134 mono_domain_unlock (domain);
2135 mono_loader_unlock ();
2139 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2140 /* This is unregistered in
2141 unregister_vtable_reflection_type() in
2143 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2146 mono_domain_unlock (domain);
2147 mono_loader_unlock ();
2149 /* make sure the parent is initialized */
2150 /*FIXME shouldn't this fail the current type?*/
2152 mono_class_vtable_full (domain, klass->parent, error);
2157 #ifndef DISABLE_REMOTING
2159 * mono_class_proxy_vtable:
2160 * \param domain the application domain
2161 * \param remove_class the remote class
2162 * \param error set on error
2163 * Creates a vtable for transparent proxies. It is basically
2164 * a copy of the real vtable of the class wrapped in \p remote_class,
2165 * but all function pointers invoke the remoting functions, and
2166 * \c vtable->klass points to the transparent proxy class, and not to \p class.
2168 * On failure returns NULL and sets \p error
2171 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type, MonoError *error)
2173 MONO_REQ_GC_UNSAFE_MODE;
2175 MonoVTable *vt, *pvt;
2176 int i, j, vtsize, extra_interface_vtsize = 0;
2177 guint32 max_interface_id;
2179 GSList *extra_interfaces = NULL;
2180 MonoClass *klass = remote_class->proxy_class;
2181 gpointer *interface_offsets;
2182 uint8_t *bitmap = NULL;
2184 size_t imt_table_bytes;
2186 #ifdef COMPRESSED_INTERFACE_BITMAP
2192 vt = mono_class_vtable (domain, klass);
2193 g_assert (vt); /*FIXME property handle failure*/
2194 max_interface_id = vt->max_interface_id;
2196 /* Calculate vtable space for extra interfaces */
2197 for (j = 0; j < remote_class->interface_count; j++) {
2198 MonoClass* iclass = remote_class->interfaces[j];
2202 /*FIXME test for interfaces with variant generic arguments*/
2203 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, iclass->interface_id))
2204 continue; /* interface implemented by the class */
2205 if (g_slist_find (extra_interfaces, iclass))
2208 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2210 method_count = mono_class_num_methods (iclass);
2212 ifaces = mono_class_get_implemented_interfaces (iclass, error);
2216 for (i = 0; i < ifaces->len; ++i) {
2217 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2218 /*FIXME test for interfaces with variant generic arguments*/
2219 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, ic->interface_id))
2220 continue; /* interface implemented by the class */
2221 if (g_slist_find (extra_interfaces, ic))
2223 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2224 method_count += mono_class_num_methods (ic);
2226 g_ptr_array_free (ifaces, TRUE);
2230 extra_interface_vtsize += method_count * sizeof (gpointer);
2231 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2234 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2235 mono_stats.imt_number_of_tables++;
2236 mono_stats.imt_tables_size += imt_table_bytes;
2238 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer);
2240 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2242 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2243 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2244 g_assert (!((gsize)pvt & 7));
2246 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer));
2248 pvt->klass = mono_defaults.transparent_proxy_class;
2249 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2250 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2252 /* initialize vtable */
2253 mono_class_setup_vtable (klass);
2254 for (i = 0; i < klass->vtable_size; ++i) {
2257 if ((cm = klass->vtable [i])) {
2258 pvt->vtable [i] = create_remoting_trampoline (domain, cm, target_type, error);
2262 pvt->vtable [i] = NULL;
2265 if (mono_class_is_abstract (klass)) {
2266 /* create trampolines for abstract methods */
2267 for (k = klass; k; k = k->parent) {
2269 gpointer iter = NULL;
2270 while ((m = mono_class_get_methods (k, &iter)))
2271 if (!pvt->vtable [m->slot]) {
2272 pvt->vtable [m->slot] = create_remoting_trampoline (domain, m, target_type, error);
2279 pvt->max_interface_id = max_interface_id;
2280 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2281 #ifdef COMPRESSED_INTERFACE_BITMAP
2282 bitmap = (uint8_t *)g_malloc0 (bsize);
2284 bitmap = (uint8_t *)mono_domain_alloc0 (domain, bsize);
2287 for (i = 0; i < klass->interface_offsets_count; ++i) {
2288 int interface_id = klass->interfaces_packed [i]->interface_id;
2289 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2292 if (extra_interfaces) {
2293 int slot = klass->vtable_size;
2299 /* Create trampolines for the methods of the interfaces */
2300 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2301 interf = (MonoClass *)list_item->data;
2303 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2307 while ((cm = mono_class_get_methods (interf, &iter))) {
2308 pvt->vtable [slot + j++] = create_remoting_trampoline (domain, cm, target_type, error);
2313 slot += mono_class_num_methods (interf);
2317 /* Now that the vtable is full, we can actually fill up the IMT */
2318 build_imt (klass, pvt, domain, interface_offsets, extra_interfaces);
2319 if (extra_interfaces) {
2320 g_slist_free (extra_interfaces);
2323 #ifdef COMPRESSED_INTERFACE_BITMAP
2324 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2325 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2326 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2329 pvt->interface_bitmap = bitmap;
2333 if (extra_interfaces)
2334 g_slist_free (extra_interfaces);
2335 #ifdef COMPRESSED_INTERFACE_BITMAP
2341 #endif /* DISABLE_REMOTING */
2344 * mono_class_field_is_special_static:
2345 * \returns whether \p field is a thread/context static field.
2348 mono_class_field_is_special_static (MonoClassField *field)
2350 MONO_REQ_GC_NEUTRAL_MODE
2352 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2354 if (mono_field_is_deleted (field))
2356 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2357 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2364 * mono_class_field_get_special_static_type:
2365 * \param field The \c MonoClassField describing the field.
2366 * \returns \c SPECIAL_STATIC_THREAD if the field is thread static, \c SPECIAL_STATIC_CONTEXT if it is context static,
2367 * \c SPECIAL_STATIC_NONE otherwise.
2370 mono_class_field_get_special_static_type (MonoClassField *field)
2372 MONO_REQ_GC_NEUTRAL_MODE
2374 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2375 return SPECIAL_STATIC_NONE;
2376 if (mono_field_is_deleted (field))
2377 return SPECIAL_STATIC_NONE;
2378 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2379 return field_is_special_static (field->parent, field);
2380 return SPECIAL_STATIC_NONE;
2384 * mono_class_has_special_static_fields:
2385 * \returns whether \p klass has any thread/context static fields.
2388 mono_class_has_special_static_fields (MonoClass *klass)
2390 MONO_REQ_GC_NEUTRAL_MODE
2392 MonoClassField *field;
2396 while ((field = mono_class_get_fields (klass, &iter))) {
2397 g_assert (field->parent == klass);
2398 if (mono_class_field_is_special_static (field))
2405 #ifndef DISABLE_REMOTING
2407 * create_remote_class_key:
2408 * Creates an array of pointers that can be used as a hash key for a remote class.
2409 * The first element of the array is the number of pointers.
2412 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2414 MONO_REQ_GC_NEUTRAL_MODE;
2419 if (remote_class == NULL) {
2420 if (mono_class_is_interface (extra_class)) {
2421 key = (void **)g_malloc (sizeof(gpointer) * 3);
2422 key [0] = GINT_TO_POINTER (2);
2423 key [1] = mono_defaults.marshalbyrefobject_class;
2424 key [2] = extra_class;
2426 key = (void **)g_malloc (sizeof(gpointer) * 2);
2427 key [0] = GINT_TO_POINTER (1);
2428 key [1] = extra_class;
2431 if (extra_class != NULL && mono_class_is_interface (extra_class)) {
2432 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2433 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2434 key [1] = remote_class->proxy_class;
2436 // Keep the list of interfaces sorted
2437 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2438 if (extra_class && remote_class->interfaces [i] > extra_class) {
2439 key [j++] = extra_class;
2442 key [j] = remote_class->interfaces [i];
2445 key [j] = extra_class;
2447 // Replace the old class. The interface list is the same
2448 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2449 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2450 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2451 for (i = 0; i < remote_class->interface_count; i++)
2452 key [2 + i] = remote_class->interfaces [i];
2460 * copy_remote_class_key:
2462 * Make a copy of KEY in the domain and return the copy.
2465 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2467 MONO_REQ_GC_NEUTRAL_MODE
2469 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2470 gpointer *mp_key = (gpointer *)mono_domain_alloc (domain, key_size);
2472 memcpy (mp_key, key, key_size);
2478 * mono_remote_class:
2479 * \param domain the application domain
2480 * \param class_name name of the remote class
2481 * \param error set on error
2482 * Creates and initializes a \c MonoRemoteClass object for a remote type.
2483 * On failure returns NULL and sets \p error
2486 mono_remote_class (MonoDomain *domain, MonoStringHandle class_name, MonoClass *proxy_class, MonoError *error)
2488 MONO_REQ_GC_UNSAFE_MODE;
2490 MonoRemoteClass *rc;
2491 gpointer* key, *mp_key;
2496 key = create_remote_class_key (NULL, proxy_class);
2498 mono_domain_lock (domain);
2499 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2503 mono_domain_unlock (domain);
2507 name = mono_string_to_utf8_mp (domain->mp, MONO_HANDLE_RAW (class_name), error);
2508 if (!is_ok (error)) {
2510 mono_domain_unlock (domain);
2514 mp_key = copy_remote_class_key (domain, key);
2518 if (mono_class_is_interface (proxy_class)) {
2519 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2520 rc->interface_count = 1;
2521 rc->interfaces [0] = proxy_class;
2522 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2524 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2525 rc->interface_count = 0;
2526 rc->proxy_class = proxy_class;
2529 rc->default_vtable = NULL;
2530 rc->xdomain_vtable = NULL;
2531 rc->proxy_class_name = name;
2532 #ifndef DISABLE_PERFCOUNTERS
2533 mono_perfcounters->loader_bytes += mono_string_length (MONO_HANDLE_RAW (class_name)) + 1;
2536 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2538 mono_domain_unlock (domain);
2543 * clone_remote_class:
2544 * Creates a copy of the remote_class, adding the provided class or interface
2546 static MonoRemoteClass*
2547 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2549 MONO_REQ_GC_NEUTRAL_MODE;
2551 MonoRemoteClass *rc;
2552 gpointer* key, *mp_key;
2554 key = create_remote_class_key (remote_class, extra_class);
2555 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2561 mp_key = copy_remote_class_key (domain, key);
2565 if (mono_class_is_interface (extra_class)) {
2567 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2568 rc->proxy_class = remote_class->proxy_class;
2569 rc->interface_count = remote_class->interface_count + 1;
2571 // Keep the list of interfaces sorted, since the hash key of
2572 // the remote class depends on this
2573 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2574 if (remote_class->interfaces [i] > extra_class && i == j)
2575 rc->interfaces [j++] = extra_class;
2576 rc->interfaces [j] = remote_class->interfaces [i];
2579 rc->interfaces [j] = extra_class;
2581 // Replace the old class. The interface array is the same
2582 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2583 rc->proxy_class = extra_class;
2584 rc->interface_count = remote_class->interface_count;
2585 if (rc->interface_count > 0)
2586 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2589 rc->default_vtable = NULL;
2590 rc->xdomain_vtable = NULL;
2591 rc->proxy_class_name = remote_class->proxy_class_name;
2593 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2599 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxyHandle rp, MonoError *error)
2601 MONO_REQ_GC_UNSAFE_MODE;
2605 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2606 mono_domain_lock (domain);
2607 gint32 target_domain_id = MONO_HANDLE_GETVAL (rp, target_domain_id);
2608 if (target_domain_id != -1) {
2609 if (remote_class->xdomain_vtable == NULL)
2610 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN, error);
2611 mono_domain_unlock (domain);
2612 mono_loader_unlock ();
2613 return_val_if_nok (error, NULL);
2614 return remote_class->xdomain_vtable;
2616 if (remote_class->default_vtable == NULL) {
2617 MonoReflectionTypeHandle reftype = MONO_HANDLE_NEW (MonoReflectionType, NULL);
2618 MONO_HANDLE_GET (reftype, rp, class_to_proxy);
2620 MonoType *type = MONO_HANDLE_GETVAL (reftype, type);
2621 MonoClass *klass = mono_class_from_mono_type (type);
2623 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)))
2624 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP, error);
2627 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN, error);
2628 /* N.B. both branches of the if modify error */
2629 if (!is_ok (error)) {
2630 mono_domain_unlock (domain);
2631 mono_loader_unlock ();
2636 mono_domain_unlock (domain);
2637 mono_loader_unlock ();
2638 return remote_class->default_vtable;
2642 * mono_upgrade_remote_class:
2643 * \param domain the application domain
2644 * \param tproxy the proxy whose remote class has to be upgraded.
2645 * \param klass class to which the remote class can be casted.
2646 * \param error set on error
2647 * Updates the vtable of the remote class by adding the necessary method slots
2648 * and interface offsets so it can be safely casted to klass. klass can be a
2649 * class or an interface. On success returns TRUE, on failure returns FALSE and sets \p error.
2652 mono_upgrade_remote_class (MonoDomain *domain, MonoObjectHandle proxy_object, MonoClass *klass, MonoError *error)
2654 MONO_REQ_GC_UNSAFE_MODE;
2658 MonoTransparentProxyHandle tproxy = MONO_HANDLE_CAST (MonoTransparentProxy, proxy_object);
2659 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (tproxy, remote_class);
2661 gboolean redo_vtable;
2662 if (mono_class_is_interface (klass)) {
2665 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2666 if (remote_class->interfaces [i] == klass)
2667 redo_vtable = FALSE;
2670 redo_vtable = (remote_class->proxy_class != klass);
2673 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2674 mono_domain_lock (domain);
2676 MonoRemoteClass *fresh_remote_class = clone_remote_class (domain, remote_class, klass);
2677 MONO_HANDLE_SETVAL (tproxy, remote_class, MonoRemoteClass*, fresh_remote_class);
2678 MonoRealProxyHandle real_proxy = MONO_HANDLE_NEW (MonoRealProxy, NULL);
2679 MONO_HANDLE_GET (real_proxy, tproxy, rp);
2680 MONO_HANDLE_SETVAL (proxy_object, vtable, MonoVTable*, mono_remote_class_vtable (domain, fresh_remote_class, real_proxy, error));
2686 mono_domain_unlock (domain);
2687 mono_loader_unlock ();
2688 return is_ok (error);
2690 #endif /* DISABLE_REMOTING */
2694 * mono_object_get_virtual_method:
2695 * \param obj object to operate on.
2696 * \param method method
2697 * Retrieves the \c MonoMethod that would be called on \p obj if \p obj is passed as
2698 * the instance of a callvirt of \p method.
2701 mono_object_get_virtual_method (MonoObject *obj_raw, MonoMethod *method)
2703 MONO_REQ_GC_UNSAFE_MODE;
2704 HANDLE_FUNCTION_ENTER ();
2706 MONO_HANDLE_DCL (MonoObject, obj);
2707 MonoMethod *result = mono_object_handle_get_virtual_method (obj, method, &error);
2708 mono_error_assert_ok (&error);
2709 HANDLE_FUNCTION_RETURN_VAL (result);
2713 * mono_object_handle_get_virtual_method:
2714 * \param obj object to operate on.
2715 * \param method method
2716 * Retrieves the \c MonoMethod that would be called on \p obj if \p obj is passed as
2717 * the instance of a callvirt of \p method.
2720 mono_object_handle_get_virtual_method (MonoObjectHandle obj, MonoMethod *method, MonoError *error)
2724 gboolean is_proxy = FALSE;
2725 MonoClass *klass = mono_handle_class (obj);
2726 if (mono_class_is_transparent_proxy (klass)) {
2727 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), remote_class);
2728 klass = remote_class->proxy_class;
2731 return class_get_virtual_method (klass, method, is_proxy, error);
2735 class_get_virtual_method (MonoClass *klass, MonoMethod *method, gboolean is_proxy, MonoError *error)
2740 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2743 mono_class_setup_vtable (klass);
2744 MonoMethod **vtable = klass->vtable;
2746 if (method->slot == -1) {
2747 /* method->slot might not be set for instances of generic methods */
2748 if (method->is_inflated) {
2749 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2750 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2753 g_assert_not_reached ();
2757 MonoMethod *res = NULL;
2758 /* check method->slot is a valid index: perform isinstance? */
2759 if (method->slot != -1) {
2760 if (mono_class_is_interface (method->klass)) {
2762 gboolean variance_used = FALSE;
2763 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2764 g_assert (iface_offset > 0);
2765 res = vtable [iface_offset + method->slot];
2768 res = vtable [method->slot];
2772 #ifndef DISABLE_REMOTING
2774 /* It may be an interface, abstract class method or generic method */
2775 if (!res || mono_method_signature (res)->generic_param_count)
2778 /* generic methods demand invoke_with_check */
2779 if (mono_method_signature (res)->generic_param_count)
2780 res = mono_marshal_get_remoting_invoke_with_check (res);
2783 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2784 res = mono_cominterop_get_invoke (res);
2787 res = mono_marshal_get_remoting_invoke (res);
2792 if (method->is_inflated) {
2793 /* Have to inflate the result */
2794 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, error);
2802 do_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2804 MONO_REQ_GC_UNSAFE_MODE;
2806 MonoObject *result = NULL;
2808 g_assert (callbacks.runtime_invoke);
2812 MONO_PROFILER_RAISE (method_begin_invoke, (method));
2814 result = callbacks.runtime_invoke (method, obj, params, exc, error);
2816 MONO_PROFILER_RAISE (method_end_invoke, (method));
2818 if (!mono_error_ok (error))
2825 * mono_runtime_invoke:
2826 * \param method method to invoke
2827 * \param obj object instance
2828 * \param params arguments to the method
2829 * \param exc exception information.
2830 * Invokes the method represented by \p method on the object \p obj.
2831 * \p obj is the \c this pointer, it should be NULL for static
2832 * methods, a \c MonoObject* for object instances and a pointer to
2833 * the value type for value types.
2835 * The params array contains the arguments to the method with the
2836 * same convention: \c MonoObject* pointers for object instances and
2837 * pointers to the value type otherwise.
2839 * From unmanaged code you'll usually use the
2840 * \c mono_runtime_invoke variant.
2842 * Note that this function doesn't handle virtual methods for
2843 * you, it will exec the exact method you pass: we still need to
2844 * expose a function to lookup the derived class implementation
2845 * of a virtual method (there are examples of this in the code,
2848 * You can pass NULL as the \p exc argument if you don't want to
2849 * catch exceptions, otherwise, \c *exc will be set to the exception
2850 * thrown, if any. if an exception is thrown, you can't use the
2851 * \c MonoObject* result from the function.
2853 * If the method returns a value type, it is boxed in an object
2857 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2862 res = mono_runtime_try_invoke (method, obj, params, exc, &error);
2863 if (*exc == NULL && !mono_error_ok(&error)) {
2864 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
2866 mono_error_cleanup (&error);
2868 res = mono_runtime_invoke_checked (method, obj, params, &error);
2869 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
2875 * mono_runtime_try_invoke:
2876 * \param method method to invoke
2877 * \param obj object instance
2878 * \param params arguments to the method
2879 * \param exc exception information.
2880 * \param error set on error
2881 * Invokes the method represented by \p method on the object \p obj.
2883 * \p obj is the \c this pointer, it should be NULL for static
2884 * methods, a \c MonoObject* for object instances and a pointer to
2885 * the value type for value types.
2887 * The params array contains the arguments to the method with the
2888 * same convention: \c MonoObject* pointers for object instances and
2889 * pointers to the value type otherwise.
2891 * From unmanaged code you'll usually use the
2892 * mono_runtime_invoke() variant.
2894 * Note that this function doesn't handle virtual methods for
2895 * you, it will exec the exact method you pass: we still need to
2896 * expose a function to lookup the derived class implementation
2897 * of a virtual method (there are examples of this in the code,
2900 * For this function, you must not pass NULL as the \p exc argument if
2901 * you don't want to catch exceptions, use
2902 * mono_runtime_invoke_checked(). If an exception is thrown, you
2903 * can't use the \c MonoObject* result from the function.
2905 * If this method cannot be invoked, \p error will be set and \p exc and
2906 * the return value must not be used.
2908 * If the method returns a value type, it is boxed in an object
2912 mono_runtime_try_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError* error)
2914 MONO_REQ_GC_UNSAFE_MODE;
2916 g_assert (exc != NULL);
2918 if (mono_runtime_get_no_exec ())
2919 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2921 return do_runtime_invoke (method, obj, params, exc, error);
2925 * mono_runtime_invoke_checked:
2926 * \param method method to invoke
2927 * \param obj object instance
2928 * \param params arguments to the method
2929 * \param error set on error
2930 * Invokes the method represented by \p method on the object \p obj.
2932 * \p obj is the \c this pointer, it should be NULL for static
2933 * methods, a \c MonoObject* for object instances and a pointer to
2934 * the value type for value types.
2936 * The \p params array contains the arguments to the method with the
2937 * same convention: \c MonoObject* pointers for object instances and
2938 * pointers to the value type otherwise.
2940 * From unmanaged code you'll usually use the
2941 * mono_runtime_invoke() variant.
2943 * Note that this function doesn't handle virtual methods for
2944 * you, it will exec the exact method you pass: we still need to
2945 * expose a function to lookup the derived class implementation
2946 * of a virtual method (there are examples of this in the code,
2949 * If an exception is thrown, you can't use the \c MonoObject* result
2950 * from the function.
2952 * If this method cannot be invoked, \p error will be set. If the
2953 * method throws an exception (and we're in coop mode) the exception
2954 * will be set in \p error.
2956 * If the method returns a value type, it is boxed in an object
2960 mono_runtime_invoke_checked (MonoMethod *method, void *obj, void **params, MonoError* error)
2962 MONO_REQ_GC_UNSAFE_MODE;
2964 if (mono_runtime_get_no_exec ())
2965 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2967 return do_runtime_invoke (method, obj, params, NULL, error);
2971 * mono_method_get_unmanaged_thunk:
2972 * \param method method to generate a thunk for.
2974 * Returns an \c unmanaged->managed thunk that can be used to call
2975 * a managed method directly from C.
2977 * The thunk's C signature closely matches the managed signature:
2979 * C#: <code>public bool Equals (object obj);</code>
2981 * C: <code>typedef MonoBoolean (*Equals)(MonoObject*, MonoObject*, MonoException**);</code>
2983 * The 1st (<code>this</code>) parameter must not be used with static methods:
2985 * C#: <code>public static bool ReferenceEquals (object a, object b);</code>
2987 * C: <code>typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*, MonoException**);</code>
2989 * The last argument must be a non-null \c MonoException* pointer.
2990 * It has "out" semantics. After invoking the thunk, \c *ex will be NULL if no
2991 * exception has been thrown in managed code. Otherwise it will point
2992 * to the \c MonoException* caught by the thunk. In this case, the result of
2993 * the thunk is undefined:
2996 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2998 * MonoException *ex = NULL;
3000 * Equals func = mono_method_get_unmanaged_thunk (method);
3002 * MonoBoolean res = func (thisObj, objToCompare, &ex);
3006 * // handle exception
3011 * The calling convention of the thunk matches the platform's default
3012 * convention. This means that under Windows, C declarations must
3013 * contain the \c __stdcall attribute:
3015 * C: <code>typedef MonoBoolean (__stdcall *Equals)(MonoObject*, MonoObject*, MonoException**);</code>
3019 * Value type arguments and return values are treated as they were objects:
3021 * C#: <code>public static Rectangle Intersect (Rectangle a, Rectangle b);</code>
3022 * C: <code>typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);</code>
3024 * Arguments must be properly boxed upon trunk's invocation, while return
3025 * values must be unboxed.
3028 mono_method_get_unmanaged_thunk (MonoMethod *method)
3030 MONO_REQ_GC_NEUTRAL_MODE;
3031 MONO_REQ_API_ENTRYPOINT;
3036 g_assert (!mono_threads_is_coop_enabled ());
3038 MONO_ENTER_GC_UNSAFE;
3039 method = mono_marshal_get_thunk_invoke_wrapper (method);
3040 res = mono_compile_method_checked (method, &error);
3041 mono_error_cleanup (&error);
3042 MONO_EXIT_GC_UNSAFE;
3048 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
3050 MONO_REQ_GC_UNSAFE_MODE;
3054 /* object fields cannot be byref, so we don't need a
3056 gpointer *p = (gpointer*)dest;
3063 case MONO_TYPE_BOOLEAN:
3065 case MONO_TYPE_U1: {
3066 guint8 *p = (guint8*)dest;
3067 *p = value ? *(guint8*)value : 0;
3072 case MONO_TYPE_CHAR: {
3073 guint16 *p = (guint16*)dest;
3074 *p = value ? *(guint16*)value : 0;
3077 #if SIZEOF_VOID_P == 4
3082 case MONO_TYPE_U4: {
3083 gint32 *p = (gint32*)dest;
3084 *p = value ? *(gint32*)value : 0;
3087 #if SIZEOF_VOID_P == 8
3092 case MONO_TYPE_U8: {
3093 gint64 *p = (gint64*)dest;
3094 *p = value ? *(gint64*)value : 0;
3097 case MONO_TYPE_R4: {
3098 float *p = (float*)dest;
3099 *p = value ? *(float*)value : 0;
3102 case MONO_TYPE_R8: {
3103 double *p = (double*)dest;
3104 *p = value ? *(double*)value : 0;
3107 case MONO_TYPE_STRING:
3108 case MONO_TYPE_SZARRAY:
3109 case MONO_TYPE_CLASS:
3110 case MONO_TYPE_OBJECT:
3111 case MONO_TYPE_ARRAY:
3112 mono_gc_wbarrier_generic_store (dest, deref_pointer ? *(MonoObject **)value : (MonoObject *)value);
3114 case MONO_TYPE_FNPTR:
3115 case MONO_TYPE_PTR: {
3116 gpointer *p = (gpointer*)dest;
3117 *p = deref_pointer? *(gpointer*)value: value;
3120 case MONO_TYPE_VALUETYPE:
3121 /* note that 't' and 'type->type' can be different */
3122 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3123 t = mono_class_enum_basetype (type->data.klass)->type;
3126 MonoClass *klass = mono_class_from_mono_type (type);
3127 int size = mono_class_value_size (klass, NULL);
3129 mono_gc_bzero_atomic (dest, size);
3131 mono_gc_wbarrier_value_copy (dest, value, 1, klass);
3134 case MONO_TYPE_GENERICINST:
3135 t = type->data.generic_class->container_class->byval_arg.type;
3138 g_error ("got type %x", type->type);
3143 * mono_field_set_value:
3144 * \param obj Instance object
3145 * \param field \c MonoClassField describing the field to set
3146 * \param value The value to be set
3148 * Sets the value of the field described by \p field in the object instance \p obj
3149 * to the value passed in \p value. This method should only be used for instance
3150 * fields. For static fields, use \c mono_field_static_set_value.
3152 * The value must be in the native format of the field type.
3155 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3157 MONO_REQ_GC_UNSAFE_MODE;
3161 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3163 dest = (char*)obj + field->offset;
3164 mono_copy_value (field->type, dest, value, FALSE);
3168 * mono_field_static_set_value:
3169 * \param field \c MonoClassField describing the field to set
3170 * \param value The value to be set
3171 * Sets the value of the static field described by \p field
3172 * to the value passed in \p value.
3173 * The value must be in the native format of the field type.
3176 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3178 MONO_REQ_GC_UNSAFE_MODE;
3182 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3183 /* you cant set a constant! */
3184 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3186 if (field->offset == -1) {
3187 /* Special static */
3190 mono_domain_lock (vt->domain);
3191 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3192 mono_domain_unlock (vt->domain);
3193 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3195 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3197 mono_copy_value (field->type, dest, value, FALSE);
3201 * mono_vtable_get_static_field_data:
3203 * Internal use function: return a pointer to the memory holding the static fields
3204 * for a class or NULL if there are no static fields.
3205 * This is exported only for use by the debugger.
3208 mono_vtable_get_static_field_data (MonoVTable *vt)
3210 MONO_REQ_GC_NEUTRAL_MODE
3212 if (!vt->has_static_fields)
3214 return vt->vtable [vt->klass->vtable_size];
3218 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3220 MONO_REQ_GC_UNSAFE_MODE;
3224 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3225 if (field->offset == -1) {
3226 /* Special static */
3229 mono_domain_lock (vt->domain);
3230 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3231 mono_domain_unlock (vt->domain);
3232 src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3234 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3237 src = (guint8*)obj + field->offset;
3244 * mono_field_get_value:
3245 * \param obj Object instance
3246 * \param field \c MonoClassField describing the field to fetch information from
3247 * \param value pointer to the location where the value will be stored
3248 * Use this routine to get the value of the field \p field in the object
3251 * The pointer provided by value must be of the field type, for reference
3252 * types this is a \c MonoObject*, for value types its the actual pointer to
3260 * mono_field_get_value (obj, int_field, &i);
3264 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3266 MONO_REQ_GC_UNSAFE_MODE;
3272 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3274 src = (char*)obj + field->offset;
3275 mono_copy_value (field->type, value, src, TRUE);
3279 * mono_field_get_value_object:
3280 * \param domain domain where the object will be created (if boxing)
3281 * \param field \c MonoClassField describing the field to fetch information from
3282 * \param obj The object instance for the field.
3283 * \returns a new \c MonoObject with the value from the given field. If the
3284 * field represents a value type, the value is boxed.
3287 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3290 MonoObject* result = mono_field_get_value_object_checked (domain, field, obj, &error);
3291 mono_error_assert_ok (&error);
3296 * mono_field_get_value_object_checked:
3297 * \param domain domain where the object will be created (if boxing)
3298 * \param field \c MonoClassField describing the field to fetch information from
3299 * \param obj The object instance for the field.
3300 * \param error Set on error.
3301 * \returns a new \c MonoObject with the value from the given field. If the
3302 * field represents a value type, the value is boxed. On error returns NULL and sets \p error.
3305 mono_field_get_value_object_checked (MonoDomain *domain, MonoClassField *field, MonoObject *obj, MonoError *error)
3307 MONO_REQ_GC_UNSAFE_MODE;
3313 MonoVTable *vtable = NULL;
3315 gboolean is_static = FALSE;
3316 gboolean is_ref = FALSE;
3317 gboolean is_literal = FALSE;
3318 gboolean is_ptr = FALSE;
3319 MonoType *type = mono_field_get_type_checked (field, error);
3321 return_val_if_nok (error, NULL);
3323 switch (type->type) {
3324 case MONO_TYPE_STRING:
3325 case MONO_TYPE_OBJECT:
3326 case MONO_TYPE_CLASS:
3327 case MONO_TYPE_ARRAY:
3328 case MONO_TYPE_SZARRAY:
3333 case MONO_TYPE_BOOLEAN:
3336 case MONO_TYPE_CHAR:
3345 case MONO_TYPE_VALUETYPE:
3346 is_ref = type->byref;
3348 case MONO_TYPE_GENERICINST:
3349 is_ref = !mono_type_generic_inst_is_valuetype (type);
3355 g_error ("type 0x%x not handled in "
3356 "mono_field_get_value_object", type->type);
3360 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3363 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3367 vtable = mono_class_vtable_full (domain, field->parent, error);
3368 return_val_if_nok (error, NULL);
3370 if (!vtable->initialized) {
3371 mono_runtime_class_init_full (vtable, error);
3372 return_val_if_nok (error, NULL);
3381 get_default_field_value (domain, field, &o, error);
3382 return_val_if_nok (error, NULL);
3383 } else if (is_static) {
3384 mono_field_static_get_value_checked (vtable, field, &o, error);
3385 return_val_if_nok (error, NULL);
3387 mono_field_get_value (obj, field, &o);
3393 static MonoMethod *m;
3399 MonoClass *ptr_klass = mono_class_get_pointer_class ();
3400 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3406 get_default_field_value (domain, field, v, error);
3407 return_val_if_nok (error, NULL);
3408 } else if (is_static) {
3409 mono_field_static_get_value_checked (vtable, field, v, error);
3410 return_val_if_nok (error, NULL);
3412 mono_field_get_value (obj, field, v);
3415 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3416 args [0] = ptr ? *ptr : NULL;
3417 args [1] = mono_type_get_object_checked (mono_domain_get (), type, error);
3418 return_val_if_nok (error, NULL);
3420 o = mono_runtime_invoke_checked (m, NULL, args, error);
3421 return_val_if_nok (error, NULL);
3426 /* boxed value type */
3427 klass = mono_class_from_mono_type (type);
3429 if (mono_class_is_nullable (klass))
3430 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass, error);
3432 o = mono_object_new_checked (domain, klass, error);
3433 return_val_if_nok (error, NULL);
3434 v = ((gchar *) o) + sizeof (MonoObject);
3437 get_default_field_value (domain, field, v, error);
3438 return_val_if_nok (error, NULL);
3439 } else if (is_static) {
3440 mono_field_static_get_value_checked (vtable, field, v, error);
3441 return_val_if_nok (error, NULL);
3443 mono_field_get_value (obj, field, v);
3450 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value, MonoError *error)
3452 MONO_REQ_GC_UNSAFE_MODE;
3456 const char *p = blob;
3457 mono_metadata_decode_blob_size (p, &p);
3460 case MONO_TYPE_BOOLEAN:
3463 *(guint8 *) value = *p;
3465 case MONO_TYPE_CHAR:
3468 *(guint16*) value = read16 (p);
3472 *(guint32*) value = read32 (p);
3476 *(guint64*) value = read64 (p);
3479 readr4 (p, (float*) value);
3482 readr8 (p, (double*) value);
3484 case MONO_TYPE_STRING:
3485 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob, error);
3487 case MONO_TYPE_CLASS:
3488 *(gpointer*) value = NULL;
3492 g_warning ("type 0x%02x should not be in constant table", type);
3498 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error)
3500 MONO_REQ_GC_NEUTRAL_MODE;
3502 MonoTypeEnum def_type;
3507 data = mono_class_get_field_default_value (field, &def_type);
3508 mono_get_constant_value_from_blob (domain, def_type, data, value, error);
3512 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3514 MONO_REQ_GC_UNSAFE_MODE;
3520 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3522 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3523 get_default_field_value (vt->domain, field, value, error);
3527 if (field->offset == -1) {
3528 /* Special static */
3529 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3530 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3532 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3534 mono_copy_value (field->type, value, src, TRUE);
3538 * mono_field_static_get_value:
3539 * \param vt vtable to the object
3540 * \param field \c MonoClassField describing the field to fetch information from
3541 * \param value where the value is returned
3542 * Use this routine to get the value of the static field \p field value.
3544 * The pointer provided by value must be of the field type, for reference
3545 * types this is a \c MonoObject*, for value types its the actual pointer to
3553 * mono_field_static_get_value (vt, int_field, &i);
3557 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3559 MONO_REQ_GC_NEUTRAL_MODE;
3562 mono_field_static_get_value_checked (vt, field, value, &error);
3563 mono_error_cleanup (&error);
3567 * mono_field_static_get_value_checked:
3568 * \param vt vtable to the object
3569 * \param field \c MonoClassField describing the field to fetch information from
3570 * \param value where the value is returned
3571 * \param error set on error
3572 * Use this routine to get the value of the static field \p field value.
3574 * The pointer provided by value must be of the field type, for reference
3575 * types this is a \c MonoObject*, for value types its the actual pointer to
3580 * mono_field_static_get_value_checked (vt, int_field, &i, error);
3581 * if (!is_ok (error)) { ... }
3583 * On failure sets \p error.
3586 mono_field_static_get_value_checked (MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3588 MONO_REQ_GC_NEUTRAL_MODE;
3590 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value, error);
3594 * mono_property_set_value:
3595 * \param prop MonoProperty to set
3596 * \param obj instance object on which to act
3597 * \param params parameters to pass to the propery
3598 * \param exc optional exception
3599 * Invokes the property's set method with the given arguments on the
3600 * object instance obj (or NULL for static properties).
3602 * You can pass NULL as the exc argument if you don't want to
3603 * catch exceptions, otherwise, \c *exc will be set to the exception
3604 * thrown, if any. if an exception is thrown, you can't use the
3605 * \c MonoObject* result from the function.
3608 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3610 MONO_REQ_GC_UNSAFE_MODE;
3613 do_runtime_invoke (prop->set, obj, params, exc, &error);
3614 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3615 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3617 mono_error_cleanup (&error);
3622 * mono_property_set_value_checked:
3623 * \param prop \c MonoProperty to set
3624 * \param obj instance object on which to act
3625 * \param params parameters to pass to the propery
3626 * \param error set on error
3627 * Invokes the property's set method with the given arguments on the
3628 * object instance \p obj (or NULL for static properties).
3629 * \returns TRUE on success. On failure returns FALSE and sets \p error.
3630 * If an exception is thrown, it will be caught and returned via \p error.
3633 mono_property_set_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3635 MONO_REQ_GC_UNSAFE_MODE;
3640 do_runtime_invoke (prop->set, obj, params, &exc, error);
3641 if (exc != NULL && is_ok (error))
3642 mono_error_set_exception_instance (error, (MonoException*)exc);
3643 return is_ok (error);
3647 * mono_property_get_value:
3648 * \param prop \c MonoProperty to fetch
3649 * \param obj instance object on which to act
3650 * \param params parameters to pass to the propery
3651 * \param exc optional exception
3652 * Invokes the property's \c get method with the given arguments on the
3653 * object instance \p obj (or NULL for static properties).
3655 * You can pass NULL as the \p exc argument if you don't want to
3656 * catch exceptions, otherwise, \c *exc will be set to the exception
3657 * thrown, if any. if an exception is thrown, you can't use the
3658 * \c MonoObject* result from the function.
3660 * \returns the value from invoking the \c get method on the property.
3663 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3665 MONO_REQ_GC_UNSAFE_MODE;
3668 MonoObject *val = do_runtime_invoke (prop->get, obj, params, exc, &error);
3669 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3670 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3672 mono_error_cleanup (&error); /* FIXME don't raise here */
3679 * mono_property_get_value_checked:
3680 * \param prop \c MonoProperty to fetch
3681 * \param obj instance object on which to act
3682 * \param params parameters to pass to the propery
3683 * \param error set on error
3684 * Invokes the property's \c get method with the given arguments on the
3685 * object instance obj (or NULL for static properties).
3687 * If an exception is thrown, you can't use the
3688 * \c MonoObject* result from the function. The exception will be propagated via \p error.
3690 * \returns the value from invoking the get method on the property. On
3691 * failure returns NULL and sets \p error.
3694 mono_property_get_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3696 MONO_REQ_GC_UNSAFE_MODE;
3699 MonoObject *val = do_runtime_invoke (prop->get, obj, params, &exc, error);
3700 if (exc != NULL && !is_ok (error))
3701 mono_error_set_exception_instance (error, (MonoException*) exc);
3709 * mono_nullable_init:
3710 * @buf: The nullable structure to initialize.
3711 * @value: the value to initialize from
3712 * @klass: the type for the object
3714 * Initialize the nullable structure pointed to by @buf from @value which
3715 * should be a boxed value type. The size of @buf should be able to hold
3716 * as much data as the @klass->instance_size (which is the number of bytes
3717 * that will be copies).
3719 * Since Nullables have variable structure, we can not define a C
3720 * structure for them.
3723 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3725 MONO_REQ_GC_UNSAFE_MODE;
3727 MonoClass *param_class = klass->cast_class;
3729 mono_class_setup_fields (klass);
3730 g_assert (klass->fields_inited);
3732 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3733 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3735 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3737 if (param_class->has_references)
3738 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3740 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3742 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3747 * mono_nullable_init_from_handle:
3748 * @buf: The nullable structure to initialize.
3749 * @value: the value to initialize from
3750 * @klass: the type for the object
3752 * Initialize the nullable structure pointed to by @buf from @value which
3753 * should be a boxed value type. The size of @buf should be able to hold
3754 * as much data as the @klass->instance_size (which is the number of bytes
3755 * that will be copies).
3757 * Since Nullables have variable structure, we can not define a C
3758 * structure for them.
3761 mono_nullable_init_from_handle (guint8 *buf, MonoObjectHandle value, MonoClass *klass)
3763 MONO_REQ_GC_UNSAFE_MODE;
3765 MonoClass *param_class = klass->cast_class;
3767 mono_class_setup_fields (klass);
3768 g_assert (klass->fields_inited);
3770 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3771 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3773 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = MONO_HANDLE_IS_NULL (value) ? 0 : 1;
3774 if (!MONO_HANDLE_IS_NULL (value)) {
3775 uint32_t value_gchandle = 0;
3776 gpointer src = mono_object_handle_pin_unbox (value, &value_gchandle);
3777 if (param_class->has_references)
3778 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), src, 1, param_class);
3780 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), src, mono_class_value_size (param_class, NULL));
3781 mono_gchandle_free (value_gchandle);
3783 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3790 * mono_nullable_box:
3791 * \param buf The buffer representing the data to be boxed
3792 * \param klass the type to box it as.
3793 * \param error set on error
3795 * Creates a boxed vtype or NULL from the \c Nullable structure pointed to by
3796 * \p buf. On failure returns NULL and sets \p error.
3799 mono_nullable_box (guint8 *buf, MonoClass *klass, MonoError *error)
3801 MONO_REQ_GC_UNSAFE_MODE;
3804 MonoClass *param_class = klass->cast_class;
3806 mono_class_setup_fields (klass);
3807 g_assert (klass->fields_inited);
3809 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3810 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3812 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3813 MonoObject *o = mono_object_new_checked (mono_domain_get (), param_class, error);
3814 return_val_if_nok (error, NULL);
3815 if (param_class->has_references)
3816 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3818 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3826 * mono_get_delegate_invoke:
3827 * \param klass The delegate class
3828 * \returns the \c MonoMethod for the \c Invoke method in the delegate class or NULL if \p klass is a broken delegate type
3831 mono_get_delegate_invoke (MonoClass *klass)
3833 MONO_REQ_GC_NEUTRAL_MODE;
3837 /* This is called at runtime, so avoid the slower search in metadata */
3838 mono_class_setup_methods (klass);
3839 if (mono_class_has_failure (klass))
3841 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3846 * mono_get_delegate_begin_invoke:
3847 * \param klass The delegate class
3848 * \returns the \c MonoMethod for the \c BeginInvoke method in the delegate class or NULL if \p 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 * \param klass The delegate class
3868 * \returns the \c MonoMethod for the \c EndInvoke method in the delegate class or NULL if \p klass is a broken delegate type
3871 mono_get_delegate_end_invoke (MonoClass *klass)
3873 MONO_REQ_GC_NEUTRAL_MODE;
3877 /* This is called at runtime, so avoid the slower search in metadata */
3878 mono_class_setup_methods (klass);
3879 if (mono_class_has_failure (klass))
3881 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3886 * mono_runtime_delegate_invoke:
3887 * \param delegate pointer to a delegate object.
3888 * \param params parameters for the delegate.
3889 * \param exc Pointer to the exception result.
3891 * Invokes the delegate method \p delegate with the parameters provided.
3893 * You can pass NULL as the \p exc argument if you don't want to
3894 * catch exceptions, otherwise, \c *exc will be set to the exception
3895 * thrown, if any. if an exception is thrown, you can't use the
3896 * \c MonoObject* result from the function.
3899 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3901 MONO_REQ_GC_UNSAFE_MODE;
3905 MonoObject *result = mono_runtime_delegate_try_invoke (delegate, params, exc, &error);
3907 mono_error_cleanup (&error);
3910 if (!is_ok (&error))
3911 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
3915 MonoObject *result = mono_runtime_delegate_invoke_checked (delegate, params, &error);
3916 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
3922 * mono_runtime_delegate_try_invoke:
3923 * \param delegate pointer to a delegate object.
3924 * \param params parameters for the delegate.
3925 * \param exc Pointer to the exception result.
3926 * \param error set on error
3927 * Invokes the delegate method \p delegate with the parameters provided.
3929 * You can pass NULL as the \p exc argument if you don't want to
3930 * catch exceptions, otherwise, \c *exc will be set to the exception
3931 * thrown, if any. On failure to execute, \p error will be set.
3932 * if an exception is thrown, you can't use the
3933 * \c MonoObject* result from the function.
3936 mono_runtime_delegate_try_invoke (MonoObject *delegate, void **params, MonoObject **exc, MonoError *error)
3938 MONO_REQ_GC_UNSAFE_MODE;
3942 MonoClass *klass = delegate->vtable->klass;
3945 im = mono_get_delegate_invoke (klass);
3947 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3950 o = mono_runtime_try_invoke (im, delegate, params, exc, error);
3952 o = mono_runtime_invoke_checked (im, delegate, params, error);
3959 * mono_runtime_delegate_invoke_checked:
3960 * \param delegate pointer to a delegate object.
3961 * \param params parameters for the delegate.
3962 * \param error set on error
3963 * Invokes the delegate method \p delegate with the parameters provided.
3964 * On failure \p error will be set and you can't use the \c MonoObject*
3965 * result from the function.
3968 mono_runtime_delegate_invoke_checked (MonoObject *delegate, void **params, MonoError *error)
3971 return mono_runtime_delegate_try_invoke (delegate, params, NULL, error);
3974 static char **main_args = NULL;
3975 static int num_main_args = 0;
3978 * mono_runtime_get_main_args:
3979 * \returns A \c MonoArray with the arguments passed to the main program
3982 mono_runtime_get_main_args (void)
3984 MONO_REQ_GC_UNSAFE_MODE;
3986 MonoArray *result = mono_runtime_get_main_args_checked (&error);
3987 mono_error_assert_ok (&error);
3992 * mono_runtime_get_main_args_checked:
3993 * \param error set on error
3994 * \returns a \c MonoArray with the arguments passed to the main
3995 * program. On failure returns NULL and sets \p error.
3998 mono_runtime_get_main_args_checked (MonoError *error)
4002 MonoDomain *domain = mono_domain_get ();
4006 res = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, num_main_args, error);
4007 return_val_if_nok (error, NULL);
4009 for (i = 0; i < num_main_args; ++i) {
4010 MonoString *arg = mono_string_new_checked (domain, main_args [i], error);
4011 return_val_if_nok (error, NULL);
4012 mono_array_setref (res, i, arg);
4019 free_main_args (void)
4021 MONO_REQ_GC_NEUTRAL_MODE;
4025 for (i = 0; i < num_main_args; ++i)
4026 g_free (main_args [i]);
4033 * mono_runtime_set_main_args:
4034 * \param argc number of arguments from the command line
4035 * \param argv array of strings from the command line
4036 * Set the command line arguments from an embedding application that doesn't otherwise call
4037 * \c mono_runtime_run_main.
4040 mono_runtime_set_main_args (int argc, char* argv[])
4042 MONO_REQ_GC_NEUTRAL_MODE;
4047 main_args = g_new0 (char*, argc);
4048 num_main_args = argc;
4050 for (i = 0; i < argc; ++i) {
4053 utf8_arg = mono_utf8_from_external (argv[i]);
4054 if (utf8_arg == NULL) {
4055 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
4056 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4060 main_args [i] = utf8_arg;
4067 * Prepare an array of arguments in order to execute a standard Main()
4068 * method (argc/argv contains the executable name). This method also
4069 * sets the command line argument value needed by System.Environment.
4073 prepare_run_main (MonoMethod *method, int argc, char *argv[])
4075 MONO_REQ_GC_UNSAFE_MODE;
4079 MonoArray *args = NULL;
4080 MonoDomain *domain = mono_domain_get ();
4081 gchar *utf8_fullpath;
4082 MonoMethodSignature *sig;
4084 g_assert (method != NULL);
4086 mono_thread_set_main (mono_thread_current ());
4088 main_args = g_new0 (char*, argc);
4089 num_main_args = argc;
4091 if (!g_path_is_absolute (argv [0])) {
4092 gchar *basename = g_path_get_basename (argv [0]);
4093 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
4097 utf8_fullpath = mono_utf8_from_external (fullpath);
4098 if(utf8_fullpath == NULL) {
4099 /* Printing the arg text will cause glib to
4100 * whinge about "Invalid UTF-8", but at least
4101 * its relevant, and shows the problem text
4104 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
4105 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4112 utf8_fullpath = mono_utf8_from_external (argv[0]);
4113 if(utf8_fullpath == NULL) {
4114 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
4115 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4120 main_args [0] = utf8_fullpath;
4122 for (i = 1; i < argc; ++i) {
4125 utf8_arg=mono_utf8_from_external (argv[i]);
4126 if(utf8_arg==NULL) {
4127 /* Ditto the comment about Invalid UTF-8 here */
4128 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
4129 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4133 main_args [i] = utf8_arg;
4138 sig = mono_method_signature (method);
4140 g_print ("Unable to load Main method.\n");
4144 if (sig->param_count) {
4145 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, argc, &error);
4146 mono_error_assert_ok (&error);
4147 for (i = 0; i < argc; ++i) {
4148 /* The encodings should all work, given that
4149 * we've checked all these args for the
4152 gchar *str = mono_utf8_from_external (argv [i]);
4153 MonoString *arg = mono_string_new_checked (domain, str, &error);
4154 mono_error_assert_ok (&error);
4155 mono_array_setref (args, i, arg);
4159 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, 0, &error);
4160 mono_error_assert_ok (&error);
4163 mono_assembly_set_main (method->klass->image->assembly);
4169 * mono_runtime_run_main:
4170 * \param method the method to start the application with (usually <code>Main</code>)
4171 * \param argc number of arguments from the command line
4172 * \param argv array of strings from the command line
4173 * \param exc excetption results
4174 * Execute a standard \c Main method (\p argc / \p argv contains the
4175 * executable name). This method also sets the command line argument value
4176 * needed by \c System.Environment.
4179 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
4182 MONO_REQ_GC_UNSAFE_MODE;
4185 MonoArray *args = prepare_run_main (method, argc, argv);
4188 res = mono_runtime_try_exec_main (method, args, exc);
4190 res = mono_runtime_exec_main_checked (method, args, &error);
4191 mono_error_raise_exception (&error); /* OK to throw, external only without a better alternative */
4197 * mono_runtime_run_main_checked:
4198 * \param method the method to start the application with (usually \c Main)
4199 * \param argc number of arguments from the command line
4200 * \param argv array of strings from the command line
4201 * \param error set on error
4203 * Execute a standard \c Main method (\p argc / \p argv contains the
4204 * executable name). This method also sets the command line argument value
4205 * needed by \c System.Environment. On failure sets \p error.
4208 mono_runtime_run_main_checked (MonoMethod *method, int argc, char* argv[],
4212 MonoArray *args = prepare_run_main (method, argc, argv);
4213 return mono_runtime_exec_main_checked (method, args, error);
4217 * mono_runtime_try_run_main:
4218 * \param method the method to start the application with (usually \c Main)
4219 * \param argc number of arguments from the command line
4220 * \param argv array of strings from the command line
4221 * \param exc set if \c Main throws an exception
4222 * \param error set if \c Main can't be executed
4223 * Execute a standard \c Main method (\p argc / \p argv contains the executable
4224 * name). This method also sets the command line argument value needed
4225 * by \c System.Environment. On failure sets \p error if Main can't be
4226 * executed or \p exc if it threw an exception.
4229 mono_runtime_try_run_main (MonoMethod *method, int argc, char* argv[],
4233 MonoArray *args = prepare_run_main (method, argc, argv);
4234 return mono_runtime_try_exec_main (method, args, exc);
4239 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4241 static MonoMethod *serialize_method;
4247 if (!serialize_method) {
4248 MonoClass *klass = mono_class_get_remoting_services_class ();
4249 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
4252 if (!serialize_method) {
4257 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
4262 array = mono_runtime_try_invoke (serialize_method, NULL, params, exc, &error);
4263 if (*exc == NULL && !mono_error_ok (&error))
4264 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert serialize_object to MonoError */
4266 mono_error_cleanup (&error);
4275 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4277 MONO_REQ_GC_UNSAFE_MODE;
4279 static MonoMethod *deserialize_method;
4285 if (!deserialize_method) {
4286 MonoClass *klass = mono_class_get_remoting_services_class ();
4287 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
4289 if (!deserialize_method) {
4297 result = mono_runtime_try_invoke (deserialize_method, NULL, params, exc, &error);
4298 if (*exc == NULL && !mono_error_ok (&error))
4299 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert deserialize_object to MonoError */
4301 mono_error_cleanup (&error);
4309 #ifndef DISABLE_REMOTING
4311 make_transparent_proxy (MonoObject *obj, MonoError *error)
4313 MONO_REQ_GC_UNSAFE_MODE;
4315 static MonoMethod *get_proxy_method;
4317 MonoDomain *domain = mono_domain_get ();
4318 MonoRealProxy *real_proxy;
4319 MonoReflectionType *reflection_type;
4320 MonoTransparentProxy *transparent_proxy;
4324 if (!get_proxy_method)
4325 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
4327 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
4329 real_proxy = (MonoRealProxy*) mono_object_new_checked (domain, mono_defaults.real_proxy_class, error);
4330 return_val_if_nok (error, NULL);
4331 reflection_type = mono_type_get_object_checked (domain, &obj->vtable->klass->byval_arg, error);
4332 return_val_if_nok (error, NULL);
4334 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
4335 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
4337 MonoObject *exc = NULL;
4339 transparent_proxy = (MonoTransparentProxy*) mono_runtime_try_invoke (get_proxy_method, real_proxy, NULL, &exc, error);
4340 if (exc != NULL && is_ok (error))
4341 mono_error_set_exception_instance (error, (MonoException*)exc);
4343 return (MonoObject*) transparent_proxy;
4345 #endif /* DISABLE_REMOTING */
4348 * mono_object_xdomain_representation
4349 * \param obj an object
4350 * \param target_domain a domain
4351 * \param error set on error.
4352 * Creates a representation of obj in the domain \p target_domain. This
4353 * is either a copy of \p obj arrived through via serialization and
4354 * deserialization or a proxy, depending on whether the object is
4355 * serializable or marshal by ref. \p obj must not be in \p target_domain.
4356 * If the object cannot be represented in \p target_domain, NULL is
4357 * returned and \p error is set appropriately.
4360 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoError *error)
4362 MONO_REQ_GC_UNSAFE_MODE;
4365 MonoObject *deserialized = NULL;
4367 #ifndef DISABLE_REMOTING
4368 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
4369 deserialized = make_transparent_proxy (obj, error);
4374 gboolean failure = FALSE;
4375 MonoDomain *domain = mono_domain_get ();
4376 MonoObject *serialized;
4377 MonoObject *exc = NULL;
4379 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
4380 serialized = serialize_object (obj, &failure, &exc);
4381 mono_domain_set_internal_with_options (target_domain, FALSE);
4383 deserialized = deserialize_object (serialized, &failure, &exc);
4384 if (domain != target_domain)
4385 mono_domain_set_internal_with_options (domain, FALSE);
4387 mono_error_set_exception_instance (error, (MonoException*)exc);
4390 return deserialized;
4393 /* Used in call_unhandled_exception_delegate */
4395 create_unhandled_exception_eventargs (MonoObject *exc, MonoError *error)
4397 MONO_REQ_GC_UNSAFE_MODE;
4402 MonoMethod *method = NULL;
4403 MonoBoolean is_terminating = TRUE;
4406 klass = mono_class_get_unhandled_exception_event_args_class ();
4407 mono_class_init (klass);
4409 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4410 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
4414 args [1] = &is_terminating;
4416 obj = mono_object_new_checked (mono_domain_get (), klass, error);
4417 return_val_if_nok (error, NULL);
4419 mono_runtime_invoke_checked (method, obj, args, error);
4420 return_val_if_nok (error, NULL);
4425 /* Used in mono_unhandled_exception */
4427 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4428 MONO_REQ_GC_UNSAFE_MODE;
4431 MonoObject *e = NULL;
4433 MonoDomain *current_domain = mono_domain_get ();
4435 if (domain != current_domain)
4436 mono_domain_set_internal_with_options (domain, FALSE);
4438 g_assert (domain == mono_object_domain (domain->domain));
4440 if (mono_object_domain (exc) != domain) {
4442 exc = mono_object_xdomain_representation (exc, domain, &error);
4444 if (!is_ok (&error)) {
4445 MonoError inner_error;
4446 MonoException *serialization_exc = mono_error_convert_to_exception (&error);
4447 exc = mono_object_xdomain_representation ((MonoObject*)serialization_exc, domain, &inner_error);
4448 mono_error_assert_ok (&inner_error);
4450 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4451 "System.Runtime.Serialization", "SerializationException",
4452 "Could not serialize unhandled exception.");
4456 g_assert (mono_object_domain (exc) == domain);
4458 pa [0] = domain->domain;
4459 pa [1] = create_unhandled_exception_eventargs (exc, &error);
4460 mono_error_assert_ok (&error);
4461 mono_runtime_delegate_try_invoke (delegate, pa, &e, &error);
4462 if (!is_ok (&error)) {
4464 e = (MonoObject*)mono_error_convert_to_exception (&error);
4466 mono_error_cleanup (&error);
4469 if (domain != current_domain)
4470 mono_domain_set_internal_with_options (current_domain, FALSE);
4473 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4474 if (!mono_error_ok (&error)) {
4475 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4476 mono_error_cleanup (&error);
4478 g_warning ("exception inside UnhandledException handler: %s\n", msg);
4484 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4487 * mono_runtime_unhandled_exception_policy_set:
4488 * \param policy the new policy
4489 * This is a VM internal routine.
4490 * Sets the runtime policy for handling unhandled exceptions.
4493 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4494 runtime_unhandled_exception_policy = policy;
4498 * mono_runtime_unhandled_exception_policy_get:
4500 * This is a VM internal routine.
4502 * Gets the runtime policy for handling unhandled exceptions.
4504 MonoRuntimeUnhandledExceptionPolicy
4505 mono_runtime_unhandled_exception_policy_get (void) {
4506 return runtime_unhandled_exception_policy;
4510 * mono_unhandled_exception:
4511 * \param exc exception thrown
4512 * This is a VM internal routine.
4514 * We call this function when we detect an unhandled exception
4515 * in the default domain.
4517 * It invokes the \c UnhandledException event in \c AppDomain or prints
4518 * a warning to the console
4521 mono_unhandled_exception (MonoObject *exc_raw)
4524 HANDLE_FUNCTION_ENTER ();
4525 MONO_HANDLE_DCL (MonoObject, exc);
4526 error_init (&error);
4527 mono_unhandled_exception_checked (exc, &error);
4528 mono_error_assert_ok (&error);
4529 HANDLE_FUNCTION_RETURN ();
4533 * mono_unhandled_exception:
4534 * @exc: exception thrown
4536 * This is a VM internal routine.
4538 * We call this function when we detect an unhandled exception
4539 * in the default domain.
4541 * It invokes the * UnhandledException event in AppDomain or prints
4542 * a warning to the console
4545 mono_unhandled_exception_checked (MonoObjectHandle exc, MonoError *error)
4547 MONO_REQ_GC_UNSAFE_MODE;
4550 MonoClassField *field;
4551 MonoDomain *current_domain, *root_domain;
4552 MonoObjectHandle current_appdomain_delegate = MONO_HANDLE_NEW (MonoObject, NULL);
4554 MonoClass *klass = mono_handle_class (exc);
4555 if (mono_class_has_parent (klass, mono_defaults.threadabortexception_class))
4558 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4561 current_domain = mono_domain_get ();
4562 root_domain = mono_get_root_domain ();
4564 MonoObjectHandle root_appdomain_delegate = MONO_HANDLE_NEW (MonoObject, mono_field_get_value_object_checked (root_domain, field, (MonoObject*) root_domain->domain, error)); /* FIXME use handles for mono_field_get_value_object_checked */
4565 return_if_nok (error);
4566 if (current_domain != root_domain) {
4567 MONO_HANDLE_ASSIGN (current_appdomain_delegate, MONO_HANDLE_NEW (MonoObject, mono_field_get_value_object_checked (current_domain, field, (MonoObject*) current_domain->domain, error))); /* FIXME use handles for mono_field_get_value_object_checked */
4568 return_if_nok (error);
4571 if (MONO_HANDLE_IS_NULL (current_appdomain_delegate) && MONO_HANDLE_IS_NULL (root_appdomain_delegate)) {
4572 mono_print_unhandled_exception (MONO_HANDLE_RAW (exc)); /* FIXME use handles for mono_print_unhandled_exception */
4574 /* unhandled exception callbacks must not be aborted */
4575 mono_threads_begin_abort_protected_block ();
4576 if (!MONO_HANDLE_IS_NULL (root_appdomain_delegate))
4577 call_unhandled_exception_delegate (root_domain, MONO_HANDLE_RAW (root_appdomain_delegate), MONO_HANDLE_RAW (exc)); /* FIXME use handles in call_unhandled_exception_delegate */
4578 if (!MONO_HANDLE_IS_NULL (current_appdomain_delegate))
4579 call_unhandled_exception_delegate (current_domain, MONO_HANDLE_RAW (current_appdomain_delegate), MONO_HANDLE_RAW (exc));
4580 mono_threads_end_abort_protected_block ();
4583 /* set exitcode only if we will abort the process */
4584 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4585 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4587 mono_environment_exitcode_set (1);
4592 * mono_runtime_exec_managed_code:
4593 * \param domain Application domain
4594 * \param main_func function to invoke from the execution thread
4595 * \param main_args parameter to the main_func
4596 * Launch a new thread to execute a function
4598 * \p main_func is called back from the thread with main_args as the
4599 * parameter. The callback function is expected to start \c Main
4600 * eventually. This function then waits for all managed threads to
4602 * It is not necessary anymore to execute managed code in a subthread,
4603 * so this function should not be used anymore by default: just
4604 * execute the code and then call mono_thread_manage().
4607 mono_runtime_exec_managed_code (MonoDomain *domain,
4608 MonoMainThreadFunc main_func,
4612 mono_thread_create_checked (domain, main_func, main_args, &error);
4613 mono_error_assert_ok (&error);
4615 mono_thread_manage ();
4619 prepare_thread_to_exec_main (MonoDomain *domain, MonoMethod *method)
4621 MonoInternalThread* thread = mono_thread_internal_current ();
4622 MonoCustomAttrInfo* cinfo;
4623 gboolean has_stathread_attribute;
4625 if (!domain->entry_assembly) {
4628 MonoAssembly *assembly;
4630 assembly = method->klass->image->assembly;
4631 domain->entry_assembly = assembly;
4632 /* Domains created from another domain already have application_base and configuration_file set */
4633 if (domain->setup->application_base == NULL) {
4634 MonoString *basedir = mono_string_new_checked (domain, assembly->basedir, &error);
4635 mono_error_assert_ok (&error);
4636 MONO_OBJECT_SETREF (domain->setup, application_base, basedir);
4639 if (domain->setup->configuration_file == NULL) {
4640 str = g_strconcat (assembly->image->name, ".config", NULL);
4641 MonoString *config_file = mono_string_new_checked (domain, str, &error);
4642 mono_error_assert_ok (&error);
4643 MONO_OBJECT_SETREF (domain->setup, configuration_file, config_file);
4645 mono_domain_set_options_from_config (domain);
4649 MonoError cattr_error;
4650 cinfo = mono_custom_attrs_from_method_checked (method, &cattr_error);
4651 mono_error_cleanup (&cattr_error); /* FIXME warn here? */
4653 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, mono_class_get_sta_thread_attribute_class ());
4655 mono_custom_attrs_free (cinfo);
4657 has_stathread_attribute = FALSE;
4659 if (has_stathread_attribute) {
4660 thread->apartment_state = ThreadApartmentState_STA;
4662 thread->apartment_state = ThreadApartmentState_MTA;
4664 mono_thread_init_apartment_state ();
4669 do_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4671 MONO_REQ_GC_UNSAFE_MODE;
4681 /* FIXME: check signature of method */
4682 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4684 res = mono_runtime_invoke_checked (method, NULL, pa, error);
4686 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4689 mono_environment_exitcode_set (rval);
4691 mono_runtime_invoke_checked (method, NULL, pa, error);
4703 do_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4705 MONO_REQ_GC_UNSAFE_MODE;
4715 /* FIXME: check signature of method */
4716 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4717 MonoError inner_error;
4719 res = mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4720 if (*exc == NULL && !mono_error_ok (&inner_error))
4721 *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4723 mono_error_cleanup (&inner_error);
4726 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4730 mono_environment_exitcode_set (rval);
4732 MonoError inner_error;
4733 mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4734 if (*exc == NULL && !mono_error_ok (&inner_error))
4735 *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4737 mono_error_cleanup (&inner_error);
4742 /* If the return type of Main is void, only
4743 * set the exitcode if an exception was thrown
4744 * (we don't want to blow away an
4745 * explicitly-set exit code)
4748 mono_environment_exitcode_set (rval);
4756 * Execute a standard Main() method (args doesn't contain the
4760 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4763 prepare_thread_to_exec_main (mono_object_domain (args), method);
4765 int rval = do_try_exec_main (method, args, exc);
4768 int rval = do_exec_main_checked (method, args, &error);
4769 mono_error_raise_exception (&error); /* OK to throw, external only with no better option */
4775 * Execute a standard Main() method (args doesn't contain the
4778 * On failure sets @error
4781 mono_runtime_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4784 prepare_thread_to_exec_main (mono_object_domain (args), method);
4785 return do_exec_main_checked (method, args, error);
4789 * Execute a standard Main() method (args doesn't contain the
4792 * On failure sets @error if Main couldn't be executed, or @exc if it threw an exception.
4795 mono_runtime_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4797 prepare_thread_to_exec_main (mono_object_domain (args), method);
4798 return do_try_exec_main (method, args, exc);
4803 /** invoke_array_extract_argument:
4804 * @params: array of arguments to the method.
4805 * @i: the index of the argument to extract.
4806 * @t: ith type from the method signature.
4807 * @has_byref_nullables: outarg - TRUE if method expects a byref nullable argument
4808 * @error: set on error.
4810 * Given an array of method arguments, return the ith one using the corresponding type
4811 * to perform necessary unboxing. If method expects a ref nullable argument, writes TRUE to @has_byref_nullables.
4813 * On failure sets @error and returns NULL.
4816 invoke_array_extract_argument (MonoArray *params, int i, MonoType *t, gboolean* has_byref_nullables, MonoError *error)
4818 MonoType *t_orig = t;
4819 gpointer result = NULL;
4825 case MONO_TYPE_BOOLEAN:
4828 case MONO_TYPE_CHAR:
4837 case MONO_TYPE_VALUETYPE:
4838 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (t_orig))) {
4839 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4840 result = mono_array_get (params, MonoObject*, i);
4842 *has_byref_nullables = TRUE;
4844 /* MS seems to create the objects if a null is passed in */
4845 gboolean was_null = FALSE;
4846 if (!mono_array_get (params, MonoObject*, i)) {
4847 MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (t_orig), error);
4848 return_val_if_nok (error, NULL);
4849 mono_array_setref (params, i, o);
4855 * We can't pass the unboxed vtype byref to the callee, since
4856 * that would mean the callee would be able to modify boxed
4857 * primitive types. So we (and MS) make a copy of the boxed
4858 * object, pass that to the callee, and replace the original
4859 * boxed object in the arg array with the copy.
4861 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4862 MonoObject *copy = mono_value_box_checked (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig), error);
4863 return_val_if_nok (error, NULL);
4864 mono_array_setref (params, i, copy);
4867 result = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4868 if (!t->byref && was_null)
4869 mono_array_setref (params, i, NULL);
4872 case MONO_TYPE_STRING:
4873 case MONO_TYPE_OBJECT:
4874 case MONO_TYPE_CLASS:
4875 case MONO_TYPE_ARRAY:
4876 case MONO_TYPE_SZARRAY:
4878 result = mono_array_addr (params, MonoObject*, i);
4879 // FIXME: I need to check this code path
4881 result = mono_array_get (params, MonoObject*, i);
4883 case MONO_TYPE_GENERICINST:
4885 t = &t->data.generic_class->container_class->this_arg;
4887 t = &t->data.generic_class->container_class->byval_arg;
4889 case MONO_TYPE_PTR: {
4892 /* The argument should be an IntPtr */
4893 arg = mono_array_get (params, MonoObject*, i);
4897 g_assert (arg->vtable->klass == mono_defaults.int_class);
4898 result = ((MonoIntPtr*)arg)->m_value;
4903 g_error ("type 0x%x not handled in mono_runtime_invoke_array", t_orig->type);
4908 * mono_runtime_invoke_array:
4909 * \param method method to invoke
4910 * \param obj object instance
4911 * \param params arguments to the method
4912 * \param exc exception information.
4913 * Invokes the method represented by \p method on the object \p obj.
4915 * \p obj is the \c this pointer, it should be NULL for static
4916 * methods, a \c MonoObject* for object instances and a pointer to
4917 * the value type for value types.
4919 * The \p params array contains the arguments to the method with the
4920 * same convention: \c MonoObject* pointers for object instances and
4921 * pointers to the value type otherwise. The \c _invoke_array
4922 * variant takes a C# \c object[] as the params argument (\c MonoArray*):
4923 * in this case the value types are boxed inside the
4924 * respective reference representation.
4926 * From unmanaged code you'll usually use the
4927 * mono_runtime_invoke_checked() variant.
4929 * Note that this function doesn't handle virtual methods for
4930 * you, it will exec the exact method you pass: we still need to
4931 * expose a function to lookup the derived class implementation
4932 * of a virtual method (there are examples of this in the code,
4935 * You can pass NULL as the \p exc argument if you don't want to
4936 * catch exceptions, otherwise, \c *exc will be set to the exception
4937 * thrown, if any. if an exception is thrown, you can't use the
4938 * \c MonoObject* result from the function.
4940 * If the method returns a value type, it is boxed in an object
4944 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4949 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, exc, &error);
4951 mono_error_cleanup (&error);
4954 if (!is_ok (&error))
4955 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
4959 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, NULL, &error);
4960 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
4966 * mono_runtime_invoke_array_checked:
4967 * \param method method to invoke
4968 * \param obj object instance
4969 * \param params arguments to the method
4970 * \param error set on failure.
4971 * Invokes the method represented by \p method on the object \p obj.
4973 * \p obj is the \c this pointer, it should be NULL for static
4974 * methods, a \c MonoObject* for object instances and a pointer to
4975 * the value type for value types.
4977 * The \p params array contains the arguments to the method with the
4978 * same convention: \c MonoObject* pointers for object instances and
4979 * pointers to the value type otherwise. The \c _invoke_array
4980 * variant takes a C# \c object[] as the \p params argument (\c MonoArray*):
4981 * in this case the value types are boxed inside the
4982 * respective reference representation.
4984 * From unmanaged code you'll usually use the
4985 * mono_runtime_invoke_checked() variant.
4987 * Note that this function doesn't handle virtual methods for
4988 * you, it will exec the exact method you pass: we still need to
4989 * expose a function to lookup the derived class implementation
4990 * of a virtual method (there are examples of this in the code,
4993 * On failure or exception, \p error will be set. In that case, you
4994 * can't use the \c MonoObject* result from the function.
4996 * If the method returns a value type, it is boxed in an object
5000 mono_runtime_invoke_array_checked (MonoMethod *method, void *obj, MonoArray *params,
5004 return mono_runtime_try_invoke_array (method, obj, params, NULL, error);
5008 * mono_runtime_try_invoke_array:
5009 * \param method method to invoke
5010 * \param obj object instance
5011 * \param params arguments to the method
5012 * \param exc exception information.
5013 * \param error set on failure.
5014 * Invokes the method represented by \p method on the object \p obj.
5016 * \p obj is the \c this pointer, it should be NULL for static
5017 * methods, a \c MonoObject* for object instances and a pointer to
5018 * the value type for value types.
5020 * The \p params array contains the arguments to the method with the
5021 * same convention: \c MonoObject* pointers for object instances and
5022 * pointers to the value type otherwise. The \c _invoke_array
5023 * variant takes a C# \c object[] as the params argument (\c MonoArray*):
5024 * in this case the value types are boxed inside the
5025 * respective reference representation.
5027 * From unmanaged code you'll usually use the
5028 * mono_runtime_invoke_checked() variant.
5030 * Note that this function doesn't handle virtual methods for
5031 * you, it will exec the exact method you pass: we still need to
5032 * expose a function to lookup the derived class implementation
5033 * of a virtual method (there are examples of this in the code,
5036 * You can pass NULL as the \p exc argument if you don't want to catch
5037 * exceptions, otherwise, \c *exc will be set to the exception thrown, if
5038 * any. On other failures, \p error will be set. If an exception is
5039 * thrown or there's an error, you can't use the \c MonoObject* result
5040 * from the function.
5042 * If the method returns a value type, it is boxed in an object
5046 mono_runtime_try_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
5047 MonoObject **exc, MonoError *error)
5049 MONO_REQ_GC_UNSAFE_MODE;
5053 MonoMethodSignature *sig = mono_method_signature (method);
5054 gpointer *pa = NULL;
5057 gboolean has_byref_nullables = FALSE;
5059 if (NULL != params) {
5060 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
5061 for (i = 0; i < mono_array_length (params); i++) {
5062 MonoType *t = sig->params [i];
5063 pa [i] = invoke_array_extract_argument (params, i, t, &has_byref_nullables, error);
5064 return_val_if_nok (error, NULL);
5068 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
5071 if (mono_class_is_nullable (method->klass)) {
5072 /* Need to create a boxed vtype instead */
5078 return mono_value_box_checked (mono_domain_get (), method->klass->cast_class, pa [0], error);
5083 obj = mono_object_new_checked (mono_domain_get (), method->klass, error);
5084 mono_error_assert_ok (error);
5085 g_assert (obj); /*maybe we should raise a TLE instead?*/
5086 #ifndef DISABLE_REMOTING
5087 if (mono_object_is_transparent_proxy (obj)) {
5088 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
5091 if (method->klass->valuetype)
5092 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
5095 } else if (method->klass->valuetype) {
5096 obj = mono_value_box_checked (mono_domain_get (), method->klass, obj, error);
5097 return_val_if_nok (error, NULL);
5101 mono_runtime_try_invoke (method, o, pa, exc, error);
5103 mono_runtime_invoke_checked (method, o, pa, error);
5106 return (MonoObject *)obj;
5108 if (mono_class_is_nullable (method->klass)) {
5109 MonoObject *nullable;
5111 /* Convert the unboxed vtype into a Nullable structure */
5112 nullable = mono_object_new_checked (mono_domain_get (), method->klass, error);
5113 return_val_if_nok (error, NULL);
5115 MonoObject *boxed = mono_value_box_checked (mono_domain_get (), method->klass->cast_class, obj, error);
5116 return_val_if_nok (error, NULL);
5117 mono_nullable_init ((guint8 *)mono_object_unbox (nullable), boxed, method->klass);
5118 obj = mono_object_unbox (nullable);
5121 /* obj must be already unboxed if needed */
5123 res = mono_runtime_try_invoke (method, obj, pa, exc, error);
5125 res = mono_runtime_invoke_checked (method, obj, pa, error);
5127 return_val_if_nok (error, NULL);
5129 if (sig->ret->type == MONO_TYPE_PTR) {
5130 MonoClass *pointer_class;
5131 static MonoMethod *box_method;
5133 MonoObject *box_exc;
5136 * The runtime-invoke wrapper returns a boxed IntPtr, need to
5137 * convert it to a Pointer object.
5139 pointer_class = mono_class_get_pointer_class ();
5141 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
5143 g_assert (res->vtable->klass == mono_defaults.int_class);
5144 box_args [0] = ((MonoIntPtr*)res)->m_value;
5145 box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, error);
5146 return_val_if_nok (error, NULL);
5148 res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, error);
5149 g_assert (box_exc == NULL);
5150 mono_error_assert_ok (error);
5153 if (has_byref_nullables) {
5155 * The runtime invoke wrapper already converted byref nullables back,
5156 * and stored them in pa, we just need to copy them back to the
5159 for (i = 0; i < mono_array_length (params); i++) {
5160 MonoType *t = sig->params [i];
5162 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
5163 mono_array_setref (params, i, pa [i]);
5173 * \param klass the class of the object that we want to create
5174 * \returns a newly created object whose definition is
5175 * looked up using \p klass. This will not invoke any constructors,
5176 * so the consumer of this routine has to invoke any constructors on
5177 * its own to initialize the object.
5179 * It returns NULL on failure.
5182 mono_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_cleanup (&error);
5195 ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
5197 MONO_REQ_GC_UNSAFE_MODE;
5201 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5203 mono_error_set_pending_exception (&error);
5208 * mono_object_new_checked:
5209 * \param klass the class of the object that we want to create
5210 * \param error set on error
5211 * \returns a newly created object whose definition is
5212 * looked up using \p klass. This will not invoke any constructors,
5213 * so the consumer of this routine has to invoke any constructors on
5214 * its own to initialize the object.
5216 * It returns NULL on failure and sets \p error.
5219 mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
5221 MONO_REQ_GC_UNSAFE_MODE;
5225 vtable = mono_class_vtable (domain, klass);
5226 g_assert (vtable); /* FIXME don't swallow the error */
5228 MonoObject *o = mono_object_new_specific_checked (vtable, error);
5233 * mono_object_new_pinned:
5235 * Same as mono_object_new, but the returned object will be pinned.
5236 * For SGEN, these objects will only be freed at appdomain unload.
5239 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
5241 MONO_REQ_GC_UNSAFE_MODE;
5247 vtable = mono_class_vtable (domain, klass);
5248 g_assert (vtable); /* FIXME don't swallow the error */
5250 MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
5252 if (G_UNLIKELY (!o))
5253 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
5254 else if (G_UNLIKELY (vtable->klass->has_finalize))
5255 mono_object_register_finalizer (o);
5261 * mono_object_new_specific:
5262 * \param vtable the vtable of the object that we want to create
5263 * \returns A newly created object with class and domain specified
5267 mono_object_new_specific (MonoVTable *vtable)
5270 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5271 mono_error_cleanup (&error);
5277 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
5279 MONO_REQ_GC_UNSAFE_MODE;
5285 /* check for is_com_object for COM Interop */
5286 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
5289 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
5292 MonoClass *klass = mono_class_get_activation_services_class ();
5295 mono_class_init (klass);
5297 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
5299 mono_error_set_not_supported (error, "Linked away.");
5302 vtable->domain->create_proxy_for_type_method = im;
5305 pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
5306 if (!mono_error_ok (error))
5309 o = mono_runtime_invoke_checked (im, NULL, pa, error);
5310 if (!mono_error_ok (error))
5317 return mono_object_new_alloc_specific_checked (vtable, error);
5321 ves_icall_object_new_specific (MonoVTable *vtable)
5324 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5325 mono_error_set_pending_exception (&error);
5331 * mono_object_new_alloc_specific:
5332 * \param vtable virtual table for the object.
5333 * This function allocates a new \c MonoObject with the type derived
5334 * from the \p vtable information. If the class of this object has a
5335 * finalizer, then the object will be tracked for finalization.
5337 * This method might raise an exception on errors. Use the
5338 * \c mono_object_new_fast_checked method if you want to manually raise
5341 * \returns the allocated object.
5344 mono_object_new_alloc_specific (MonoVTable *vtable)
5347 MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
5348 mono_error_cleanup (&error);
5354 * mono_object_new_alloc_specific_checked:
5355 * \param vtable virtual table for the object.
5356 * \param error holds the error return value.
5358 * This function allocates a new \c MonoObject with the type derived
5359 * from the \p vtable information. If the class of this object has a
5360 * finalizer, then the object will be tracked for finalization.
5362 * If there is not enough memory, the \p error parameter will be set
5363 * and will contain a user-visible message with the amount of bytes
5364 * that were requested.
5366 * \returns the allocated object, or NULL if there is not enough memory
5369 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
5371 MONO_REQ_GC_UNSAFE_MODE;
5377 o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5379 if (G_UNLIKELY (!o))
5380 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5381 else if (G_UNLIKELY (vtable->klass->has_finalize))
5382 mono_object_register_finalizer (o);
5388 * mono_object_new_fast:
5389 * \param vtable virtual table for the object.
5391 * This function allocates a new \c MonoObject with the type derived
5392 * from the \p vtable information. The returned object is not tracked
5393 * for finalization. If your object implements a finalizer, you should
5394 * use \c mono_object_new_alloc_specific instead.
5396 * This method might raise an exception on errors. Use the
5397 * \c mono_object_new_fast_checked method if you want to manually raise
5400 * \returns the allocated object.
5403 mono_object_new_fast (MonoVTable *vtable)
5406 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5407 mono_error_cleanup (&error);
5413 * mono_object_new_fast_checked:
5414 * \param vtable virtual table for the object.
5415 * \param error holds the error return value.
5417 * This function allocates a new \c MonoObject with the type derived
5418 * from the \p vtable information. The returned object is not tracked
5419 * for finalization. If your object implements a finalizer, you should
5420 * use \c mono_object_new_alloc_specific_checked instead.
5422 * If there is not enough memory, the \p error parameter will be set
5423 * and will contain a user-visible message with the amount of bytes
5424 * that were requested.
5426 * \returns the allocated object, or NULL if there is not enough memory
5429 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
5431 MONO_REQ_GC_UNSAFE_MODE;
5437 o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5439 if (G_UNLIKELY (!o))
5440 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5446 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
5448 MONO_REQ_GC_UNSAFE_MODE;
5454 o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
5456 if (G_UNLIKELY (!o))
5457 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5458 else if (G_UNLIKELY (vtable->klass->has_finalize))
5459 mono_object_register_finalizer (o);
5465 * mono_object_new_from_token:
5466 * \param image Context where the type_token is hosted
5467 * \param token a token of the type that we want to create
5468 * \returns A newly created object whose definition is
5469 * looked up using \p token in the \p image image
5472 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
5474 MONO_REQ_GC_UNSAFE_MODE;
5480 klass = mono_class_get_checked (image, token, &error);
5481 mono_error_assert_ok (&error);
5483 result = mono_object_new_checked (domain, klass, &error);
5485 mono_error_cleanup (&error);
5492 * mono_object_clone:
5493 * \param obj the object to clone
5494 * \returns A newly created object who is a shallow copy of \p obj
5497 mono_object_clone (MonoObject *obj)
5500 MonoObject *o = mono_object_clone_checked (obj, &error);
5501 mono_error_cleanup (&error);
5507 mono_object_clone_checked (MonoObject *obj, MonoError *error)
5509 MONO_REQ_GC_UNSAFE_MODE;
5516 size = obj->vtable->klass->instance_size;
5518 if (obj->vtable->klass->rank)
5519 return (MonoObject*)mono_array_clone_checked ((MonoArray*)obj, error);
5521 o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
5523 if (G_UNLIKELY (!o)) {
5524 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5528 /* If the object doesn't contain references this will do a simple memmove. */
5529 mono_gc_wbarrier_object_copy (o, obj);
5531 if (obj->vtable->klass->has_finalize)
5532 mono_object_register_finalizer (o);
5537 * mono_array_full_copy:
5538 * \param src source array to copy
5539 * \param dest destination array
5540 * Copies the content of one array to another with exactly the same type and size.
5543 mono_array_full_copy (MonoArray *src, MonoArray *dest)
5545 MONO_REQ_GC_UNSAFE_MODE;
5548 MonoClass *klass = src->obj.vtable->klass;
5550 g_assert (klass == dest->obj.vtable->klass);
5552 size = mono_array_length (src);
5553 g_assert (size == mono_array_length (dest));
5554 size *= mono_array_element_size (klass);
5556 array_full_copy_unchecked_size (src, dest, klass, size);
5560 array_full_copy_unchecked_size (MonoArray *src, MonoArray *dest, MonoClass *klass, uintptr_t size)
5562 if (mono_gc_is_moving ()) {
5563 if (klass->element_class->valuetype) {
5564 if (klass->element_class->has_references)
5565 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
5567 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5569 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
5572 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5577 * mono_array_clone_in_domain:
5578 * \param domain the domain in which the array will be cloned into
5579 * \param array the array to clone
5580 * \param error set on error
5581 * This routine returns a copy of the array that is hosted on the
5582 * specified \c MonoDomain. On failure returns NULL and sets \p error.
5585 mono_array_clone_in_domain (MonoDomain *domain, MonoArrayHandle array_handle, MonoError *error)
5587 MONO_REQ_GC_UNSAFE_MODE;
5589 MonoArrayHandle result = MONO_HANDLE_NEW (MonoArray, NULL);
5591 MonoClass *klass = mono_handle_class (array_handle);
5595 /* Pin source array here - if bounds is non-NULL, it's a pointer into the object data */
5596 uint32_t src_handle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, array_handle), TRUE);
5598 MonoArrayBounds *array_bounds = MONO_HANDLE_GETVAL (array_handle, bounds);
5600 if (array_bounds == NULL) {
5601 size = mono_array_handle_length (array_handle);
5602 o = mono_array_new_full_handle (domain, klass, &size, NULL, error);
5605 size *= mono_array_element_size (klass);
5607 uintptr_t *sizes = (uintptr_t *)alloca (klass->rank * sizeof (uintptr_t));
5608 intptr_t *lower_bounds = (intptr_t *)alloca (klass->rank * sizeof (intptr_t));
5609 size = mono_array_element_size (klass);
5610 for (int i = 0; i < klass->rank; ++i) {
5611 sizes [i] = array_bounds [i].length;
5612 size *= array_bounds [i].length;
5613 lower_bounds [i] = array_bounds [i].lower_bound;
5615 o = mono_array_new_full_handle (domain, klass, sizes, lower_bounds, error);
5620 uint32_t dst_handle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, o), TRUE);
5621 array_full_copy_unchecked_size (MONO_HANDLE_RAW (array_handle), MONO_HANDLE_RAW (o), klass, size);
5622 mono_gchandle_free (dst_handle);
5624 MONO_HANDLE_ASSIGN (result, o);
5627 mono_gchandle_free (src_handle);
5633 * \param array the array to clone
5634 * \returns A newly created array who is a shallow copy of \p array
5637 mono_array_clone (MonoArray *array)
5639 MONO_REQ_GC_UNSAFE_MODE;
5642 MonoArray *result = mono_array_clone_checked (array, &error);
5643 mono_error_cleanup (&error);
5648 * mono_array_clone_checked:
5649 * \param array the array to clone
5650 * \param error set on error
5651 * \returns A newly created array who is a shallow copy of \p array. On
5652 * failure returns NULL and sets \p error.
5655 mono_array_clone_checked (MonoArray *array_raw, MonoError *error)
5657 MONO_REQ_GC_UNSAFE_MODE;
5658 HANDLE_FUNCTION_ENTER ();
5659 /* FIXME: callers of mono_array_clone_checked should use handles */
5661 MONO_HANDLE_DCL (MonoArray, array);
5662 MonoArrayHandle result = mono_array_clone_in_domain (MONO_HANDLE_DOMAIN (array), array, error);
5663 HANDLE_FUNCTION_RETURN_OBJ (result);
5666 /* helper macros to check for overflow when calculating the size of arrays */
5667 #ifdef MONO_BIG_ARRAYS
5668 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
5669 #define MYGUINT_MAX MYGUINT64_MAX
5670 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5671 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
5672 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5673 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
5674 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
5676 #define MYGUINT32_MAX 4294967295U
5677 #define MYGUINT_MAX MYGUINT32_MAX
5678 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5679 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
5680 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5681 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
5682 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
5686 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
5688 MONO_REQ_GC_NEUTRAL_MODE;
5692 byte_len = mono_array_element_size (klass);
5693 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
5696 if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
5698 byte_len += MONO_SIZEOF_MONO_ARRAY;
5706 * mono_array_new_full:
5707 * \param domain domain where the object is created
5708 * \param array_class array class
5709 * \param lengths lengths for each dimension in the array
5710 * \param lower_bounds lower bounds for each dimension in the array (may be NULL)
5711 * This routine creates a new array object with the given dimensions,
5712 * lower bounds and type.
5715 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
5718 MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
5719 mono_error_cleanup (&error);
5725 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
5727 MONO_REQ_GC_UNSAFE_MODE;
5729 uintptr_t byte_len = 0, len, bounds_size;
5732 MonoArrayBounds *bounds;
5738 if (!array_class->inited)
5739 mono_class_init (array_class);
5743 /* A single dimensional array with a 0 lower bound is the same as an szarray */
5744 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
5746 if (len > MONO_ARRAY_MAX_INDEX) {
5747 mono_error_set_generic_error (error, "System", "OverflowException", "");
5752 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
5754 for (i = 0; i < array_class->rank; ++i) {
5755 if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
5756 mono_error_set_generic_error (error, "System", "OverflowException", "");
5759 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5760 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5767 if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5768 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5774 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5775 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5778 byte_len = (byte_len + 3) & ~3;
5779 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5780 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5783 byte_len += bounds_size;
5786 * Following three lines almost taken from mono_object_new ():
5787 * they need to be kept in sync.
5789 vtable = mono_class_vtable_full (domain, array_class, error);
5790 return_val_if_nok (error, NULL);
5793 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5795 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5797 if (G_UNLIKELY (!o)) {
5798 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5802 array = (MonoArray*)o;
5804 bounds = array->bounds;
5807 for (i = 0; i < array_class->rank; ++i) {
5808 bounds [i].length = lengths [i];
5810 bounds [i].lower_bound = lower_bounds [i];
5819 * \param domain domain where the object is created
5820 * \param eclass element class
5821 * \param n number of array elements
5822 * This routine creates a new szarray with \p n elements of type \p eclass.
5825 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5827 MONO_REQ_GC_UNSAFE_MODE;
5830 MonoArray *result = mono_array_new_checked (domain, eclass, n, &error);
5831 mono_error_cleanup (&error);
5836 * mono_array_new_checked:
5837 * \param domain domain where the object is created
5838 * \param eclass element class
5839 * \param n number of array elements
5840 * \param error set on error
5841 * This routine creates a new szarray with \p n elements of type \p eclass.
5842 * On failure returns NULL and sets \p error.
5845 mono_array_new_checked (MonoDomain *domain, MonoClass *eclass, uintptr_t n, MonoError *error)
5851 ac = mono_array_class_get (eclass, 1);
5854 MonoVTable *vtable = mono_class_vtable_full (domain, ac, error);
5855 return_val_if_nok (error, NULL);
5857 return mono_array_new_specific_checked (vtable, n, error);
5861 ves_icall_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5864 MonoArray *arr = mono_array_new_checked (domain, eclass, n, &error);
5865 mono_error_set_pending_exception (&error);
5871 * mono_array_new_specific:
5872 * \param vtable a vtable in the appropriate domain for an initialized class
5873 * \param n number of array elements
5874 * This routine is a fast alternative to \c mono_array_new for code which
5875 * can be sure about the domain it operates in.
5878 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5881 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5882 mono_error_cleanup (&error);
5888 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
5890 MONO_REQ_GC_UNSAFE_MODE;
5897 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
5898 mono_error_set_generic_error (error, "System", "OverflowException", "");
5902 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
5903 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5906 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
5908 if (G_UNLIKELY (!o)) {
5909 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5913 return (MonoArray*)o;
5917 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
5920 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5921 mono_error_set_pending_exception (&error);
5927 * mono_string_empty_wrapper:
5929 * Returns: The same empty string instance as the managed string.Empty
5932 mono_string_empty_wrapper (void)
5934 MonoDomain *domain = mono_domain_get ();
5935 return mono_string_empty (domain);
5939 * mono_string_empty:
5941 * Returns: The same empty string instance as the managed string.Empty
5944 mono_string_empty (MonoDomain *domain)
5947 g_assert (domain->empty_string);
5948 return domain->empty_string;
5952 * mono_string_new_utf16:
5953 * \param text a pointer to an utf16 string
5954 * \param len the length of the string
5955 * \returns A newly created string object which contains \p text.
5958 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
5960 MONO_REQ_GC_UNSAFE_MODE;
5963 MonoString *res = NULL;
5964 res = mono_string_new_utf16_checked (domain, text, len, &error);
5965 mono_error_cleanup (&error);
5971 * mono_string_new_utf16_checked:
5972 * \param text a pointer to an utf16 string
5973 * \param len the length of the string
5974 * \param error written on error.
5975 * \returns A newly created string object which contains \p text.
5976 * On error, returns NULL and sets \p error.
5979 mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
5981 MONO_REQ_GC_UNSAFE_MODE;
5987 s = mono_string_new_size_checked (domain, len, error);
5989 memcpy (mono_string_chars (s), text, len * 2);
5995 * mono_string_new_utf16_handle:
5996 * \param text a pointer to an utf16 string
5997 * \param len the length of the string
5998 * \param error written on error.
5999 * \returns A newly created string object which contains \p text.
6000 * On error, returns NULL and sets \p error.
6003 mono_string_new_utf16_handle (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
6005 return MONO_HANDLE_NEW (MonoString, mono_string_new_utf16_checked (domain, text, len, error));
6009 * mono_string_new_utf32_checked:
6010 * \param text a pointer to an utf32 string
6011 * \param len the length of the string
6012 * \param error set on failure.
6013 * \returns A newly created string object which contains \p text. On failure returns NULL and sets \p error.
6016 mono_string_new_utf32_checked (MonoDomain *domain, const mono_unichar4 *text, gint32 len, MonoError *error)
6018 MONO_REQ_GC_UNSAFE_MODE;
6021 mono_unichar2 *utf16_output = NULL;
6022 gint32 utf16_len = 0;
6023 GError *gerror = NULL;
6024 glong items_written;
6027 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
6030 g_error_free (gerror);
6032 while (utf16_output [utf16_len]) utf16_len++;
6034 s = mono_string_new_size_checked (domain, utf16_len, error);
6035 return_val_if_nok (error, NULL);
6037 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
6039 g_free (utf16_output);
6045 * mono_string_new_utf32:
6046 * \param text a pointer to a UTF-32 string
6047 * \param len the length of the string
6048 * \returns A newly created string object which contains \p text.
6051 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
6054 MonoString *result = mono_string_new_utf32_checked (domain, text, len, &error);
6055 mono_error_cleanup (&error);
6060 * mono_string_new_size:
6061 * \param text a pointer to a UTF-16 string
6062 * \param len the length of the string
6063 * \returns A newly created string object of \p len
6066 mono_string_new_size (MonoDomain *domain, gint32 len)
6069 MonoString *str = mono_string_new_size_checked (domain, len, &error);
6070 mono_error_cleanup (&error);
6076 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
6078 MONO_REQ_GC_UNSAFE_MODE;
6086 /* check for overflow */
6087 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
6088 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
6092 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
6093 g_assert (size > 0);
6095 vtable = mono_class_vtable (domain, mono_defaults.string_class);
6098 s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
6100 if (G_UNLIKELY (!s)) {
6101 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", size);
6109 * mono_string_new_len:
6110 * \param text a pointer to an utf8 string
6111 * \param length number of bytes in \p text to consider
6112 * \returns A newly created string object which contains \p text.
6115 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
6117 MONO_REQ_GC_UNSAFE_MODE;
6120 MonoString *result = mono_string_new_len_checked (domain, text, length, &error);
6121 mono_error_cleanup (&error);
6126 * mono_string_new_len_checked:
6127 * \param text a pointer to an utf8 string
6128 * \param length number of bytes in \p text to consider
6129 * \param error set on error
6130 * \returns A newly created string object which contains \p text. On
6131 * failure returns NULL and sets \p error.
6134 mono_string_new_len_checked (MonoDomain *domain, const char *text, guint length, MonoError *error)
6136 MONO_REQ_GC_UNSAFE_MODE;
6140 GError *eg_error = NULL;
6141 MonoString *o = NULL;
6143 glong items_written;
6145 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
6148 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6150 g_error_free (eg_error);
6159 * \param text a pointer to a UTF-8 string
6160 * \deprecated Use \c mono_string_new_checked in new code.
6161 * This function asserts if it cannot allocate a new string.
6162 * \returns A newly created string object which contains \p text.
6165 mono_string_new (MonoDomain *domain, const char *text)
6168 MonoString *res = NULL;
6169 res = mono_string_new_checked (domain, text, &error);
6170 mono_error_assert_ok (&error);
6175 * mono_string_new_checked:
6176 * \param text a pointer to an utf8 string
6177 * \param merror set on error
6178 * \returns A newly created string object which contains \p text.
6179 * On error returns NULL and sets \p merror.
6182 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
6184 MONO_REQ_GC_UNSAFE_MODE;
6186 GError *eg_error = NULL;
6187 MonoString *o = NULL;
6189 glong items_written;
6196 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &eg_error);
6199 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6201 mono_error_set_execution_engine (error, "String conversion error: %s", eg_error->message);
6206 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
6211 MonoString *o = NULL;
6213 if (!g_utf8_validate (text, -1, &end)) {
6214 mono_error_set_argument (error, "text", "Not a valid utf8 string");
6218 len = g_utf8_strlen (text, -1);
6219 o = mono_string_new_size_checked (domain, len, error);
6222 str = mono_string_chars (o);
6224 while (text < end) {
6225 *str++ = g_utf8_get_char (text);
6226 text = g_utf8_next_char (text);
6235 * mono_string_new_wrapper:
6236 * \param text pointer to UTF-8 characters.
6237 * Helper function to create a string object from \p text in the current domain.
6240 mono_string_new_wrapper (const char *text)
6242 MONO_REQ_GC_UNSAFE_MODE;
6244 MonoDomain *domain = mono_domain_get ();
6248 MonoString *result = mono_string_new_checked (domain, text, &error);
6249 mono_error_assert_ok (&error);
6258 * \param class the class of the value
6259 * \param value a pointer to the unboxed data
6260 * \returns A newly created object which contains \p value.
6263 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
6266 MonoObject *result = mono_value_box_checked (domain, klass, value, &error);
6267 mono_error_cleanup (&error);
6272 * mono_value_box_checked:
6273 * \param domain the domain of the new object
6274 * \param class the class of the value
6275 * \param value a pointer to the unboxed data
6276 * \param error set on error
6277 * \returns A newly created object which contains \p value. On failure
6278 * returns NULL and sets \p error.
6281 mono_value_box_checked (MonoDomain *domain, MonoClass *klass, gpointer value, MonoError *error)
6283 MONO_REQ_GC_UNSAFE_MODE;
6290 g_assert (klass->valuetype);
6291 if (mono_class_is_nullable (klass))
6292 return mono_nullable_box ((guint8 *)value, klass, error);
6294 vtable = mono_class_vtable (domain, klass);
6297 size = mono_class_instance_size (klass);
6298 res = mono_object_new_alloc_specific_checked (vtable, error);
6299 return_val_if_nok (error, NULL);
6301 size = size - sizeof (MonoObject);
6303 if (mono_gc_is_moving ()) {
6304 g_assert (size == mono_class_value_size (klass, NULL));
6305 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
6307 #if NO_UNALIGNED_ACCESS
6308 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6312 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
6315 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
6318 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
6321 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
6324 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6328 if (klass->has_finalize) {
6329 mono_object_register_finalizer (res);
6330 return_val_if_nok (error, NULL);
6337 * \param dest destination pointer
6338 * \param src source pointer
6339 * \param klass a valuetype class
6340 * Copy a valuetype from \p src to \p dest. This function must be used
6341 * when \p klass contains reference fields.
6344 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
6346 MONO_REQ_GC_UNSAFE_MODE;
6348 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
6352 * mono_value_copy_array:
6353 * \param dest destination array
6354 * \param dest_idx index in the \p dest array
6355 * \param src source pointer
6356 * \param count number of items
6357 * Copy \p count valuetype items from \p src to the array \p dest at index \p dest_idx.
6358 * This function must be used when \p klass contains references fields.
6359 * Overlap is handled.
6362 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
6364 MONO_REQ_GC_UNSAFE_MODE;
6366 int size = mono_array_element_size (dest->obj.vtable->klass);
6367 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
6368 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
6369 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
6373 * mono_object_get_domain:
6374 * \param obj object to query
6375 * \returns the \c MonoDomain where the object is hosted
6378 mono_object_get_domain (MonoObject *obj)
6380 MONO_REQ_GC_UNSAFE_MODE;
6382 return mono_object_domain (obj);
6386 * mono_object_get_class:
6387 * \param obj object to query
6388 * Use this function to obtain the \c MonoClass* for a given \c MonoObject.
6389 * \returns the \c MonoClass of the object.
6392 mono_object_get_class (MonoObject *obj)
6394 MONO_REQ_GC_UNSAFE_MODE;
6396 return mono_object_class (obj);
6399 * mono_object_get_size:
6400 * \param o object to query
6401 * \returns the size, in bytes, of \p o
6404 mono_object_get_size (MonoObject* o)
6406 MONO_REQ_GC_UNSAFE_MODE;
6408 MonoClass* klass = mono_object_class (o);
6409 if (klass == mono_defaults.string_class) {
6410 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
6411 } else if (o->vtable->rank) {
6412 MonoArray *array = (MonoArray*)o;
6413 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
6414 if (array->bounds) {
6417 size += sizeof (MonoArrayBounds) * o->vtable->rank;
6421 return mono_class_instance_size (klass);
6426 * mono_object_unbox:
6427 * \param obj object to unbox
6428 * \returns a pointer to the start of the valuetype boxed in this
6431 * This method will assert if the object passed is not a valuetype.
6434 mono_object_unbox (MonoObject *obj)
6436 MONO_REQ_GC_UNSAFE_MODE;
6438 /* add assert for valuetypes? */
6439 g_assert (obj->vtable->klass->valuetype);
6440 return ((char*)obj) + sizeof (MonoObject);
6444 * mono_object_isinst:
6445 * \param obj an object
6446 * \param klass a pointer to a class
6447 * \returns \p obj if \p obj is derived from \p klass or NULL otherwise.
6450 mono_object_isinst (MonoObject *obj_raw, MonoClass *klass)
6452 MONO_REQ_GC_UNSAFE_MODE;
6454 HANDLE_FUNCTION_ENTER ();
6455 MONO_HANDLE_DCL (MonoObject, obj);
6457 MonoObjectHandle result = mono_object_handle_isinst (obj, klass, &error);
6458 mono_error_cleanup (&error);
6459 HANDLE_FUNCTION_RETURN_OBJ (result);
6464 * mono_object_isinst_checked:
6465 * \param obj an object
6466 * \param klass a pointer to a class
6467 * \param error set on error
6468 * \returns \p obj if \p obj is derived from \p klass or NULL if it isn't.
6469 * On failure returns NULL and sets \p error.
6472 mono_object_isinst_checked (MonoObject *obj_raw, MonoClass *klass, MonoError *error)
6474 MONO_REQ_GC_UNSAFE_MODE;
6476 HANDLE_FUNCTION_ENTER ();
6478 MONO_HANDLE_DCL (MonoObject, obj);
6479 MonoObjectHandle result = mono_object_handle_isinst (obj, klass, error);
6480 HANDLE_FUNCTION_RETURN_OBJ (result);
6484 * mono_object_handle_isinst:
6485 * \param obj an object
6486 * \param klass a pointer to a class
6487 * \param error set on error
6488 * \returns \p obj if \p obj is derived from \p klass or NULL if it isn't.
6489 * On failure returns NULL and sets \p error.
6492 mono_object_handle_isinst (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
6497 mono_class_init (klass);
6499 if (mono_class_is_marshalbyref (klass) || mono_class_is_interface (klass)) {
6500 return mono_object_handle_isinst_mbyref (obj, klass, error);
6503 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6505 if (!MONO_HANDLE_IS_NULL (obj) && mono_class_is_assignable_from (klass, mono_handle_class (obj)))
6506 MONO_HANDLE_ASSIGN (result, obj);
6511 * mono_object_isinst_mbyref:
6514 mono_object_isinst_mbyref (MonoObject *obj_raw, MonoClass *klass)
6516 MONO_REQ_GC_UNSAFE_MODE;
6518 HANDLE_FUNCTION_ENTER ();
6520 MONO_HANDLE_DCL (MonoObject, obj);
6521 MonoObjectHandle result = mono_object_handle_isinst_mbyref (obj, klass, &error);
6522 mono_error_cleanup (&error); /* FIXME better API that doesn't swallow the error */
6523 HANDLE_FUNCTION_RETURN_OBJ (result);
6527 mono_object_handle_isinst_mbyref (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
6531 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6533 if (MONO_HANDLE_IS_NULL (obj))
6536 MonoVTable *vt = MONO_HANDLE_GETVAL (obj, vtable);
6538 if (mono_class_is_interface (klass)) {
6539 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
6540 MONO_HANDLE_ASSIGN (result, obj);
6544 /* casting an array one of the invariant interfaces that must act as such */
6545 if (klass->is_array_special_interface) {
6546 if (mono_class_is_assignable_from (klass, vt->klass)) {
6547 MONO_HANDLE_ASSIGN (result, obj);
6552 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
6553 else if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, mono_handle_class (obj))) {
6554 MONO_HANDLE_ASSIGN (result, obj);
6558 MonoClass *oklass = vt->klass;
6559 if (mono_class_is_transparent_proxy (oklass)){
6560 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), remote_class);
6561 oklass = remote_class->proxy_class;
6564 mono_class_setup_supertypes (klass);
6565 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass)) {
6566 MONO_HANDLE_ASSIGN (result, obj);
6570 #ifndef DISABLE_REMOTING
6571 if (mono_class_is_transparent_proxy (vt->klass))
6573 MonoBoolean custom_type_info = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), custom_type_info);
6574 if (!custom_type_info)
6576 MonoDomain *domain = mono_domain_get ();
6577 MonoObjectHandle rp = MONO_HANDLE_NEW (MonoObject, NULL);
6578 MONO_HANDLE_GET (rp, MONO_HANDLE_CAST (MonoTransparentProxy, obj), rp);
6579 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
6580 MonoMethod *im = NULL;
6583 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
6585 mono_error_set_not_supported (error, "Linked away.");
6588 im = mono_object_handle_get_virtual_method (rp, im, error);
6593 MonoReflectionTypeHandle reftype = mono_type_get_object_handle (domain, &klass->byval_arg, error);
6597 pa [0] = MONO_HANDLE_RAW (reftype);
6598 pa [1] = MONO_HANDLE_RAW (obj);
6599 MonoObject *res = mono_runtime_invoke_checked (im, MONO_HANDLE_RAW (rp), pa, error);
6603 if (*(MonoBoolean *) mono_object_unbox(res)) {
6604 /* Update the vtable of the remote type, so it can safely cast to this new type */
6605 mono_upgrade_remote_class (domain, obj, klass, error);
6608 MONO_HANDLE_ASSIGN (result, obj);
6611 #endif /* DISABLE_REMOTING */
6617 * mono_object_castclass_mbyref:
6618 * \param obj an object
6619 * \param klass a pointer to a class
6620 * \returns \p obj if \p obj is derived from \p klass, returns NULL otherwise.
6623 mono_object_castclass_mbyref (MonoObject *obj_raw, MonoClass *klass)
6625 MONO_REQ_GC_UNSAFE_MODE;
6626 HANDLE_FUNCTION_ENTER ();
6628 MONO_HANDLE_DCL (MonoObject, obj);
6629 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6630 if (MONO_HANDLE_IS_NULL (obj))
6632 MONO_HANDLE_ASSIGN (result, mono_object_handle_isinst_mbyref (obj, klass, &error));
6633 mono_error_cleanup (&error);
6635 HANDLE_FUNCTION_RETURN_OBJ (result);
6639 MonoDomain *orig_domain;
6645 str_lookup (MonoDomain *domain, gpointer user_data)
6647 MONO_REQ_GC_UNSAFE_MODE;
6649 LDStrInfo *info = (LDStrInfo *)user_data;
6650 if (info->res || domain == info->orig_domain)
6652 info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
6656 mono_string_get_pinned (MonoString *str, MonoError *error)
6658 MONO_REQ_GC_UNSAFE_MODE;
6662 /* We only need to make a pinned version of a string if this is a moving GC */
6663 if (!mono_gc_is_moving ())
6667 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
6668 news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
6670 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
6671 news->length = mono_string_length (str);
6673 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6679 mono_string_is_interned_lookup (MonoString *str, int insert, MonoError *error)
6681 MONO_REQ_GC_UNSAFE_MODE;
6683 MonoGHashTable *ldstr_table;
6684 MonoString *s, *res;
6689 domain = ((MonoObject *)str)->vtable->domain;
6690 ldstr_table = domain->ldstr_table;
6692 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6698 /* Allocate outside the lock */
6700 s = mono_string_get_pinned (str, error);
6701 return_val_if_nok (error, NULL);
6704 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6709 mono_g_hash_table_insert (ldstr_table, s, s);
6714 LDStrInfo ldstr_info;
6715 ldstr_info.orig_domain = domain;
6716 ldstr_info.ins = str;
6717 ldstr_info.res = NULL;
6719 mono_domain_foreach (str_lookup, &ldstr_info);
6720 if (ldstr_info.res) {
6722 * the string was already interned in some other domain:
6723 * intern it in the current one as well.
6725 mono_g_hash_table_insert (ldstr_table, str, str);
6735 * mono_string_is_interned:
6736 * \param o String to probe
6737 * \returns Whether the string has been interned.
6740 mono_string_is_interned (MonoString *o)
6743 MonoString *result = mono_string_is_interned_lookup (o, FALSE, &error);
6744 /* This function does not fail. */
6745 mono_error_assert_ok (&error);
6750 * mono_string_intern:
6751 * \param o String to intern
6752 * Interns the string passed.
6753 * \returns The interned string.
6756 mono_string_intern (MonoString *str)
6759 MonoString *result = mono_string_intern_checked (str, &error);
6760 mono_error_assert_ok (&error);
6765 * mono_string_intern_checked:
6766 * \param o String to intern
6767 * \param error set on error.
6768 * Interns the string passed.
6769 * \returns The interned string. On failure returns NULL and sets \p error
6772 mono_string_intern_checked (MonoString *str, MonoError *error)
6774 MONO_REQ_GC_UNSAFE_MODE;
6778 return mono_string_is_interned_lookup (str, TRUE, error);
6783 * \param domain the domain where the string will be used.
6784 * \param image a metadata context
6785 * \param idx index into the user string table.
6786 * Implementation for the \c ldstr opcode.
6787 * \returns a loaded string from the \p image / \p idx combination.
6790 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
6793 MonoString *result = mono_ldstr_checked (domain, image, idx, &error);
6794 mono_error_cleanup (&error);
6799 * mono_ldstr_checked:
6800 * \param domain the domain where the string will be used.
6801 * \param image a metadata context
6802 * \param idx index into the user string table.
6803 * \param error set on error.
6804 * Implementation for the \c ldstr opcode.
6805 * \returns A loaded string from the \p image / \p idx combination.
6806 * On failure returns NULL and sets \p error.
6809 mono_ldstr_checked (MonoDomain *domain, MonoImage *image, guint32 idx, MonoError *error)
6811 MONO_REQ_GC_UNSAFE_MODE;
6814 if (image->dynamic) {
6815 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL, error);
6818 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6819 return NULL; /*FIXME we should probably be raising an exception here*/
6820 MonoString *str = mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx), error);
6826 * mono_ldstr_metadata_sig
6827 * \param domain the domain for the string
6828 * \param sig the signature of a metadata string
6829 * \param error set on error
6830 * \returns a \c MonoString for a string stored in the metadata. On
6831 * failure returns NULL and sets \p error.
6834 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error)
6836 MONO_REQ_GC_UNSAFE_MODE;
6839 const char *str = sig;
6840 MonoString *o, *interned;
6843 len2 = mono_metadata_decode_blob_size (str, &str);
6846 o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, error);
6847 return_val_if_nok (error, NULL);
6848 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
6851 guint16 *p2 = (guint16*)mono_string_chars (o);
6852 for (i = 0; i < len2; ++i) {
6853 *p2 = GUINT16_FROM_LE (*p2);
6859 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6862 return interned; /* o will get garbage collected */
6864 o = mono_string_get_pinned (o, error);
6867 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6869 mono_g_hash_table_insert (domain->ldstr_table, o, o);
6881 * Same as mono_ldstr, but return a NULL terminated utf8 string instead
6885 mono_ldstr_utf8 (MonoImage *image, guint32 idx, MonoError *error)
6891 GError *gerror = NULL;
6895 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6896 return NULL; /*FIXME we should probably be raising an exception here*/
6897 str = mono_metadata_user_string (image, idx);
6899 len2 = mono_metadata_decode_blob_size (str, &str);
6902 as = g_utf16_to_utf8 ((guint16*)str, len2, NULL, &written, &gerror);
6904 mono_error_set_argument (error, "string", "%s", gerror->message);
6905 g_error_free (gerror);
6908 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6909 if (len2 > written) {
6910 /* allocate the total length and copy the part of the string that has been converted */
6911 char *as2 = (char *)g_malloc0 (len2);
6912 memcpy (as2, as, written);
6921 * mono_string_to_utf8:
6922 * \param s a \c System.String
6923 * \deprecated Use \c mono_string_to_utf8_checked to avoid having an exception arbitrarily raised.
6924 * \returns the UTF-8 representation for \p s.
6925 * The resulting buffer needs to be freed with \c mono_free().
6928 mono_string_to_utf8 (MonoString *s)
6930 MONO_REQ_GC_UNSAFE_MODE;
6933 char *result = mono_string_to_utf8_checked (s, &error);
6935 if (!is_ok (&error)) {
6936 mono_error_cleanup (&error);
6943 * mono_string_to_utf8_checked:
6944 * \param s a \c System.String
6945 * \param error a \c MonoError.
6946 * Converts a \c MonoString to its UTF-8 representation. May fail; check
6947 * \p error to determine whether the conversion was successful.
6948 * The resulting buffer should be freed with \c mono_free().
6951 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
6953 MONO_REQ_GC_UNSAFE_MODE;
6957 GError *gerror = NULL;
6965 return g_strdup ("");
6967 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
6969 mono_error_set_argument (error, "string", "%s", gerror->message);
6970 g_error_free (gerror);
6973 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6974 if (s->length > written) {
6975 /* allocate the total length and copy the part of the string that has been converted */
6976 char *as2 = (char *)g_malloc0 (s->length);
6977 memcpy (as2, as, written);
6986 mono_string_handle_to_utf8 (MonoStringHandle s, MonoError *error)
6988 return mono_string_to_utf8_checked (MONO_HANDLE_RAW (s), error);
6992 * mono_string_to_utf8_ignore:
6993 * \param s a MonoString
6994 * Converts a \c MonoString to its UTF-8 representation. Will ignore
6995 * invalid surrogate pairs.
6996 * The resulting buffer should be freed with \c mono_free().
6999 mono_string_to_utf8_ignore (MonoString *s)
7001 MONO_REQ_GC_UNSAFE_MODE;
7010 return g_strdup ("");
7012 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
7014 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
7015 if (s->length > written) {
7016 /* allocate the total length and copy the part of the string that has been converted */
7017 char *as2 = (char *)g_malloc0 (s->length);
7018 memcpy (as2, as, written);
7027 * mono_string_to_utf8_image_ignore:
7028 * \param s a \c System.String
7029 * Same as \c mono_string_to_utf8_ignore, but allocate the string from the image mempool.
7032 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
7034 MONO_REQ_GC_UNSAFE_MODE;
7036 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
7040 * mono_string_to_utf8_mp_ignore:
7041 * \param s a \c System.String
7042 * Same as \c mono_string_to_utf8_ignore, but allocate the string from a mempool.
7045 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
7047 MONO_REQ_GC_UNSAFE_MODE;
7049 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
7054 * mono_string_to_utf16:
7055 * \param s a \c MonoString
7056 * \returns a null-terminated array of the UTF-16 chars
7057 * contained in \p s. The result must be freed with \c g_free().
7058 * This is a temporary helper until our string implementation
7059 * is reworked to always include the null-terminating char.
7062 mono_string_to_utf16 (MonoString *s)
7064 MONO_REQ_GC_UNSAFE_MODE;
7071 as = (char *)g_malloc ((s->length * 2) + 2);
7072 as [(s->length * 2)] = '\0';
7073 as [(s->length * 2) + 1] = '\0';
7076 return (gunichar2 *)(as);
7079 memcpy (as, mono_string_chars(s), s->length * 2);
7080 return (gunichar2 *)(as);
7084 * mono_string_to_utf32:
7085 * \param s a \c MonoString
7086 * \returns a null-terminated array of the UTF-32 (UCS-4) chars
7087 * contained in \p s. The result must be freed with \c g_free().
7090 mono_string_to_utf32 (MonoString *s)
7092 MONO_REQ_GC_UNSAFE_MODE;
7094 mono_unichar4 *utf32_output = NULL;
7095 GError *error = NULL;
7096 glong items_written;
7101 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
7104 g_error_free (error);
7106 return utf32_output;
7110 * mono_string_from_utf16:
7111 * \param data the UTF-16 string (LPWSTR) to convert
7112 * Converts a NULL-terminated UTF-16 string (LPWSTR) to a \c MonoString.
7113 * \returns a \c MonoString.
7116 mono_string_from_utf16 (gunichar2 *data)
7119 MonoString *result = mono_string_from_utf16_checked (data, &error);
7120 mono_error_cleanup (&error);
7125 * mono_string_from_utf16_checked:
7126 * \param data the UTF-16 string (LPWSTR) to convert
7127 * \param error set on error
7128 * Converts a NULL-terminated UTF-16 string (LPWSTR) to a \c MonoString.
7129 * \returns a \c MonoString. On failure sets \p error and returns NULL.
7132 mono_string_from_utf16_checked (gunichar2 *data, MonoError *error)
7135 MONO_REQ_GC_UNSAFE_MODE;
7138 MonoDomain *domain = mono_domain_get ();
7144 while (data [len]) len++;
7146 return mono_string_new_utf16_checked (domain, data, len, error);
7150 * mono_string_from_utf32:
7151 * \param data the UTF-32 string (LPWSTR) to convert
7152 * Converts a UTF-32 (UCS-4) string to a \c MonoString.
7153 * \returns a \c MonoString.
7156 mono_string_from_utf32 (mono_unichar4 *data)
7159 MonoString *result = mono_string_from_utf32_checked (data, &error);
7160 mono_error_cleanup (&error);
7165 * mono_string_from_utf32_checked:
7166 * \param data the UTF-32 string (LPWSTR) to convert
7167 * \param error set on error
7168 * Converts a UTF-32 (UCS-4) string to a \c MonoString.
7169 * \returns a \c MonoString. On failure returns NULL and sets \p error.
7172 mono_string_from_utf32_checked (mono_unichar4 *data, MonoError *error)
7174 MONO_REQ_GC_UNSAFE_MODE;
7177 MonoString* result = NULL;
7178 mono_unichar2 *utf16_output = NULL;
7179 GError *gerror = NULL;
7180 glong items_written;
7186 while (data [len]) len++;
7188 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &gerror);
7191 g_error_free (gerror);
7193 result = mono_string_from_utf16_checked (utf16_output, error);
7194 g_free (utf16_output);
7199 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
7201 MONO_REQ_GC_UNSAFE_MODE;
7208 r = mono_string_to_utf8_ignore (s);
7210 r = mono_string_to_utf8_checked (s, error);
7211 if (!mono_error_ok (error))
7218 len = strlen (r) + 1;
7220 mp_s = (char *)mono_mempool_alloc (mp, len);
7222 mp_s = (char *)mono_image_alloc (image, len);
7224 memcpy (mp_s, r, len);
7232 * mono_string_to_utf8_image:
7233 * \param s a \c System.String
7234 * Same as \c mono_string_to_utf8, but allocate the string from the image mempool.
7237 mono_string_to_utf8_image (MonoImage *image, MonoStringHandle s, MonoError *error)
7239 MONO_REQ_GC_UNSAFE_MODE;
7241 return mono_string_to_utf8_internal (NULL, image, MONO_HANDLE_RAW (s), FALSE, error); /* FIXME pin the string */
7245 * mono_string_to_utf8_mp:
7246 * \param s a \c System.String
7247 * Same as \c mono_string_to_utf8, but allocate the string from a mempool.
7250 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
7252 MONO_REQ_GC_UNSAFE_MODE;
7254 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
7258 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
7261 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
7263 eh_callbacks = *cbs;
7266 MonoRuntimeExceptionHandlingCallbacks *
7267 mono_get_eh_callbacks (void)
7269 return &eh_callbacks;
7273 * mono_raise_exception:
7274 * \param ex exception object
7275 * Signal the runtime that the exception \p ex has been raised in unmanaged code.
7278 mono_raise_exception (MonoException *ex)
7280 MONO_REQ_GC_UNSAFE_MODE;
7283 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
7284 * that will cause gcc to omit the function epilog, causing problems when
7285 * the JIT tries to walk the stack, since the return address on the stack
7286 * will point into the next function in the executable, not this one.
7288 eh_callbacks.mono_raise_exception (ex);
7292 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
7294 MONO_REQ_GC_UNSAFE_MODE;
7296 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
7300 * mono_wait_handle_new:
7301 * \param domain Domain where the object will be created
7302 * \param handle Handle for the wait handle
7303 * \param error set on error.
7304 * \returns A new \c MonoWaitHandle created in the given domain for the
7305 * given handle. On failure returns NULL and sets \p error.
7308 mono_wait_handle_new (MonoDomain *domain, HANDLE handle, MonoError *error)
7310 MONO_REQ_GC_UNSAFE_MODE;
7312 MonoWaitHandle *res;
7313 gpointer params [1];
7314 static MonoMethod *handle_set;
7317 res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, error);
7318 return_val_if_nok (error, NULL);
7320 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
7322 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
7324 params [0] = &handle;
7326 mono_runtime_invoke_checked (handle_set, res, params, error);
7331 mono_wait_handle_get_handle (MonoWaitHandle *handle)
7333 MONO_REQ_GC_UNSAFE_MODE;
7335 static MonoClassField *f_safe_handle = NULL;
7338 if (!f_safe_handle) {
7339 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safeWaitHandle");
7340 g_assert (f_safe_handle);
7343 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
7349 mono_runtime_capture_context (MonoDomain *domain, MonoError *error)
7351 MONO_REQ_GC_UNSAFE_MODE;
7353 RuntimeInvokeFunction runtime_invoke;
7357 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
7358 MonoMethod *method = mono_get_context_capture_method ();
7359 MonoMethod *wrapper;
7362 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
7363 domain->capture_context_runtime_invoke = mono_compile_method_checked (wrapper, error);
7364 return_val_if_nok (error, NULL);
7365 domain->capture_context_method = mono_compile_method_checked (method, error);
7366 return_val_if_nok (error, NULL);
7369 runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
7371 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
7374 * mono_async_result_new:
7375 * \param domain domain where the object will be created.
7376 * \param handle wait handle.
7377 * \param state state to pass to AsyncResult
7378 * \param data C closure data.
7379 * \param error set on error.
7380 * Creates a new MonoAsyncResult (\c AsyncResult C# class) in the given domain.
7381 * If the handle is not null, the handle is initialized to a \c MonoWaitHandle.
7382 * On failure returns NULL and sets \p error.
7385 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data, MonoError *error)
7387 MONO_REQ_GC_UNSAFE_MODE;
7390 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, error);
7391 return_val_if_nok (error, NULL);
7392 MonoObject *context = mono_runtime_capture_context (domain, error);
7393 return_val_if_nok (error, NULL);
7394 /* we must capture the execution context from the original thread */
7396 MONO_OBJECT_SETREF (res, execution_context, context);
7397 /* note: result may be null if the flow is suppressed */
7400 res->data = (void **)data;
7401 MONO_OBJECT_SETREF (res, object_data, object_data);
7402 MONO_OBJECT_SETREF (res, async_state, state);
7403 MonoWaitHandle *wait_handle = mono_wait_handle_new (domain, handle, error);
7404 return_val_if_nok (error, NULL);
7406 MONO_OBJECT_SETREF (res, handle, (MonoObject *) wait_handle);
7408 res->sync_completed = FALSE;
7409 res->completed = FALSE;
7415 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
7417 MONO_REQ_GC_UNSAFE_MODE;
7424 g_assert (ares->async_delegate);
7426 ac = (MonoAsyncCall*) ares->object_data;
7428 res = mono_runtime_delegate_invoke_checked (ares->async_delegate, (void**) &ares->async_state, &error);
7429 if (mono_error_set_pending_exception (&error))
7432 gpointer wait_event = NULL;
7434 ac->msg->exc = NULL;
7436 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args, &error);
7438 /* The exit side of the invoke must not be aborted as it would leave the runtime in an undefined state */
7439 mono_threads_begin_abort_protected_block ();
7441 if (!ac->msg->exc) {
7442 MonoException *ex = mono_error_convert_to_exception (&error);
7443 ac->msg->exc = (MonoObject *)ex;
7445 mono_error_cleanup (&error);
7448 MONO_OBJECT_SETREF (ac, res, res);
7450 mono_monitor_enter ((MonoObject*) ares);
7451 ares->completed = 1;
7453 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
7454 mono_monitor_exit ((MonoObject*) ares);
7456 if (wait_event != NULL)
7457 mono_w32event_set (wait_event);
7459 error_init (&error); //the else branch would leave it in an undefined state
7461 mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
7463 mono_threads_end_abort_protected_block ();
7465 if (mono_error_set_pending_exception (&error))
7473 mono_message_init (MonoDomain *domain,
7474 MonoMethodMessage *this_obj,
7475 MonoReflectionMethod *method,
7476 MonoArray *out_args,
7479 MONO_REQ_GC_UNSAFE_MODE;
7481 static MonoMethod *init_message_method = NULL;
7483 if (!init_message_method) {
7484 init_message_method = mono_class_get_method_from_name (mono_defaults.mono_method_message_class, "InitMessage", 2);
7485 g_assert (init_message_method != NULL);
7489 /* FIXME set domain instead? */
7490 g_assert (domain == mono_domain_get ());
7497 mono_runtime_invoke_checked (init_message_method, this_obj, args, error);
7498 return is_ok (error);
7501 #ifndef DISABLE_REMOTING
7503 * mono_remoting_invoke:
7504 * \param real_proxy pointer to a \c RealProxy object
7505 * \param msg The \c MonoMethodMessage to execute
7506 * \param exc used to store exceptions
7507 * \param out_args used to store output arguments
7508 * This is used to call \c RealProxy::Invoke(). \c RealProxy::Invoke() returns an
7509 * \c IMessage interface and it is not trivial to extract results from there. So
7510 * we call an helper method \c PrivateInvoke instead of calling
7511 * \c RealProxy::Invoke() directly.
7512 * \returns the result object.
7515 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, MonoObject **exc, MonoArray **out_args, MonoError *error)
7517 MONO_REQ_GC_UNSAFE_MODE;
7520 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
7527 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
7530 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
7532 mono_error_set_not_supported (error, "Linked away.");
7535 real_proxy->vtable->domain->private_invoke_method = im;
7538 pa [0] = real_proxy;
7543 o = mono_runtime_try_invoke (im, NULL, pa, exc, error);
7544 return_val_if_nok (error, NULL);
7551 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
7552 MonoObject **exc, MonoArray **out_args, MonoError *error)
7554 MONO_REQ_GC_UNSAFE_MODE;
7556 static MonoClass *object_array_klass;
7561 MonoMethodSignature *sig;
7563 int i, j, outarg_count = 0;
7565 #ifndef DISABLE_REMOTING
7566 if (target && mono_object_is_transparent_proxy (target)) {
7567 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
7568 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7569 target = tp->rp->unwrapped_server;
7571 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args, error);
7576 domain = mono_domain_get ();
7577 method = msg->method->method;
7578 sig = mono_method_signature (method);
7580 for (i = 0; i < sig->param_count; i++) {
7581 if (sig->params [i]->byref)
7585 if (!object_array_klass) {
7588 klass = mono_array_class_get (mono_defaults.object_class, 1);
7591 mono_memory_barrier ();
7592 object_array_klass = klass;
7595 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, error);
7596 return_val_if_nok (error, NULL);
7598 mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
7601 MonoObject *ret = mono_runtime_try_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc, error);
7602 return_val_if_nok (error, NULL);
7604 for (i = 0, j = 0; i < sig->param_count; i++) {
7605 if (sig->params [i]->byref) {
7607 arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
7608 mono_array_setref (*out_args, j, arg);
7617 * prepare_to_string_method:
7619 * @target: Set to @obj or unboxed value if a valuetype
7621 * Returns: the ToString override for @obj. If @obj is a valuetype, @target is unboxed otherwise it's @obj.
7624 prepare_to_string_method (MonoObject *obj, void **target)
7626 MONO_REQ_GC_UNSAFE_MODE;
7628 static MonoMethod *to_string = NULL;
7636 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
7638 method = mono_object_get_virtual_method (obj, to_string);
7640 // Unbox value type if needed
7641 if (mono_class_is_valuetype (mono_method_get_class (method))) {
7642 *target = mono_object_unbox (obj);
7648 * mono_object_to_string:
7649 * \param obj The object
7650 * \param exc Any exception thrown by \c ToString. May be NULL.
7651 * \returns the result of calling \c ToString on an object.
7654 mono_object_to_string (MonoObject *obj, MonoObject **exc)
7657 MonoString *s = NULL;
7659 MonoMethod *method = prepare_to_string_method (obj, &target);
7661 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
7662 if (*exc == NULL && !mono_error_ok (&error))
7663 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
7665 mono_error_cleanup (&error);
7667 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
7668 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
7675 * mono_object_to_string_checked:
7676 * \param obj The object
7677 * \param error Set on error.
7678 * \returns the result of calling \c ToString() on an object. If the
7679 * method cannot be invoked or if it raises an exception, sets \p error
7683 mono_object_to_string_checked (MonoObject *obj, MonoError *error)
7687 MonoMethod *method = prepare_to_string_method (obj, &target);
7688 return (MonoString*) mono_runtime_invoke_checked (method, target, NULL, error);
7692 * mono_object_try_to_string:
7693 * \param obj The object
7694 * \param exc Any exception thrown by \c ToString(). Must not be NULL.
7695 * \param error Set if method cannot be invoked.
7696 * \returns the result of calling \c ToString() on an object. If the
7697 * method cannot be invoked sets \p error, if it raises an exception sets \p exc,
7701 mono_object_try_to_string (MonoObject *obj, MonoObject **exc, MonoError *error)
7706 MonoMethod *method = prepare_to_string_method (obj, &target);
7707 return (MonoString*) mono_runtime_try_invoke (method, target, NULL, exc, error);
7713 get_native_backtrace (MonoException *exc_raw)
7715 HANDLE_FUNCTION_ENTER ();
7716 MONO_HANDLE_DCL(MonoException, exc);
7717 char * trace = mono_exception_handle_get_native_backtrace (exc);
7718 HANDLE_FUNCTION_RETURN_VAL (trace);
7722 * mono_print_unhandled_exception:
7723 * \param exc The exception
7724 * Prints the unhandled exception.
7727 mono_print_unhandled_exception (MonoObject *exc)
7729 MONO_REQ_GC_UNSAFE_MODE;
7732 char *message = (char*)"";
7733 gboolean free_message = FALSE;
7736 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
7737 message = g_strdup ("OutOfMemoryException");
7738 free_message = TRUE;
7739 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
7740 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
7741 free_message = TRUE;
7744 if (((MonoException*)exc)->native_trace_ips) {
7745 message = get_native_backtrace ((MonoException*)exc);
7746 free_message = TRUE;
7748 MonoObject *other_exc = NULL;
7749 str = mono_object_try_to_string (exc, &other_exc, &error);
7750 if (other_exc == NULL && !is_ok (&error))
7751 other_exc = (MonoObject*)mono_error_convert_to_exception (&error);
7753 mono_error_cleanup (&error);
7755 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
7756 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
7758 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
7759 original_backtrace, nested_backtrace);
7761 g_free (original_backtrace);
7762 g_free (nested_backtrace);
7763 free_message = TRUE;
7765 message = mono_string_to_utf8_checked (str, &error);
7766 if (!mono_error_ok (&error)) {
7767 mono_error_cleanup (&error);
7768 message = (char *) "";
7770 free_message = TRUE;
7777 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
7778 * exc->vtable->klass->name, message);
7780 g_printerr ("\nUnhandled Exception:\n%s\n", message);
7787 * mono_delegate_ctor_with_method:
7788 * \param this pointer to an uninitialized delegate object
7789 * \param target target object
7790 * \param addr pointer to native code
7791 * \param method method
7792 * \param error set on error.
7793 * Initialize a delegate and sets a specific method, not the one
7794 * associated with \p addr. This is useful when sharing generic code.
7795 * In that case \p addr will most probably not be associated with the
7796 * correct instantiation of the method.
7797 * On failure returns FALSE and sets \p error.
7800 mono_delegate_ctor_with_method (MonoObjectHandle this_obj, MonoObjectHandle target, gpointer addr, MonoMethod *method, MonoError *error)
7802 MONO_REQ_GC_UNSAFE_MODE;
7805 MonoDelegateHandle delegate = MONO_HANDLE_CAST (MonoDelegate, this_obj);
7807 g_assert (!MONO_HANDLE_IS_NULL (this_obj));
7810 MonoClass *klass = mono_handle_class (this_obj);
7811 g_assert (mono_class_has_parent (klass, mono_defaults.multicastdelegate_class));
7814 MONO_HANDLE_SETVAL (delegate, method, MonoMethod*, method);
7816 mono_stats.delegate_creations++;
7818 #ifndef DISABLE_REMOTING
7819 if (!MONO_HANDLE_IS_NULL (target) && mono_class_is_transparent_proxy (mono_handle_class (target))) {
7821 method = mono_marshal_get_remoting_invoke (method);
7822 #ifdef ENABLE_INTERPRETER
7823 //g_error ("need RuntimeMethod in method_ptr when using interpreter");
7825 MONO_HANDLE_SETVAL (delegate, method_ptr, gpointer, mono_compile_method_checked (method, error));
7826 return_val_if_nok (error, FALSE);
7827 MONO_HANDLE_SET (delegate, target, target);
7831 MONO_HANDLE_SETVAL (delegate, method_ptr, gpointer, addr);
7832 MONO_HANDLE_SET (delegate, target, target);
7835 MONO_HANDLE_SETVAL (delegate, invoke_impl, gpointer, callbacks.create_delegate_trampoline (MONO_HANDLE_DOMAIN (delegate), mono_handle_class (delegate)));
7836 if (callbacks.init_delegate)
7837 callbacks.init_delegate (MONO_HANDLE_RAW (delegate)); /* FIXME: update init_delegate callback to take a MonoDelegateHandle */
7842 * mono_delegate_ctor:
7843 * \param this pointer to an uninitialized delegate object
7844 * \param target target object
7845 * \param addr pointer to native code
7846 * \param error set on error.
7847 * This is used to initialize a delegate.
7848 * On failure returns FALSE and sets \p error.
7851 mono_delegate_ctor (MonoObjectHandle this_obj, MonoObjectHandle target, gpointer addr, MonoError *error)
7853 MONO_REQ_GC_UNSAFE_MODE;
7856 MonoDomain *domain = mono_domain_get ();
7858 MonoMethod *method = NULL;
7862 ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
7864 if (!ji && domain != mono_get_root_domain ())
7865 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
7867 method = mono_jit_info_get_method (ji);
7868 g_assert (!mono_class_is_gtd (method->klass));
7871 return mono_delegate_ctor_with_method (this_obj, target, addr, method, error);
7875 * mono_method_call_message_new:
7876 * \param method method to encapsulate
7877 * \param params parameters to the method
7878 * \param invoke optional, delegate invoke.
7879 * \param cb async callback delegate.
7880 * \param state state passed to the async callback.
7881 * \param error set on error.
7882 * Translates arguments pointers into a \c MonoMethodMessage.
7883 * On failure returns NULL and sets \p error.
7886 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
7887 MonoDelegate **cb, MonoObject **state, MonoError *error)
7889 MONO_REQ_GC_UNSAFE_MODE;
7893 MonoDomain *domain = mono_domain_get ();
7894 MonoMethodSignature *sig = mono_method_signature (method);
7895 MonoMethodMessage *msg;
7898 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
7899 return_val_if_nok (error, NULL);
7902 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, error);
7903 return_val_if_nok (error, NULL);
7904 mono_message_init (domain, msg, rm, NULL, error);
7905 return_val_if_nok (error, NULL);
7906 count = sig->param_count - 2;
7908 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
7909 return_val_if_nok (error, NULL);
7910 mono_message_init (domain, msg, rm, NULL, error);
7911 return_val_if_nok (error, NULL);
7912 count = sig->param_count;
7915 for (i = 0; i < count; i++) {
7920 if (sig->params [i]->byref)
7921 vpos = *((gpointer *)params [i]);
7925 klass = mono_class_from_mono_type (sig->params [i]);
7927 if (klass->valuetype) {
7928 arg = mono_value_box_checked (domain, klass, vpos, error);
7929 return_val_if_nok (error, NULL);
7931 arg = *((MonoObject **)vpos);
7933 mono_array_setref (msg->args, i, arg);
7936 if (cb != NULL && state != NULL) {
7937 *cb = *((MonoDelegate **)params [i]);
7939 *state = *((MonoObject **)params [i]);
7946 * mono_method_return_message_restore:
7948 * Restore results from message based processing back to arguments pointers
7951 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args, MonoError *error)
7953 MONO_REQ_GC_UNSAFE_MODE;
7957 MonoMethodSignature *sig = mono_method_signature (method);
7958 int i, j, type, size, out_len;
7960 if (out_args == NULL)
7962 out_len = mono_array_length (out_args);
7966 for (i = 0, j = 0; i < sig->param_count; i++) {
7967 MonoType *pt = sig->params [i];
7972 mono_error_set_execution_engine (error, "The proxy call returned an incorrect number of output arguments");
7976 arg = (char *)mono_array_get (out_args, gpointer, j);
7979 g_assert (type != MONO_TYPE_VOID);
7981 if (MONO_TYPE_IS_REFERENCE (pt)) {
7982 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
7985 MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
7986 size = mono_class_value_size (klass, NULL);
7987 if (klass->has_references)
7988 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
7990 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
7992 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
7993 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
8002 #ifndef DISABLE_REMOTING
8005 * mono_load_remote_field:
8006 * \param this pointer to an object
8007 * \param klass klass of the object containing \p field
8008 * \param field the field to load
8009 * \param res a storage to store the result
8010 * This method is called by the runtime on attempts to load fields of
8011 * transparent proxy objects. \p this points to such TP, \p klass is the class of
8012 * the object containing \p field. \p res is a storage location which can be
8013 * used to store the result.
8014 * \returns an address pointing to the value of field.
8017 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
8020 gpointer result = mono_load_remote_field_checked (this_obj, klass, field, res, &error);
8021 mono_error_cleanup (&error);
8026 * mono_load_remote_field_checked:
8027 * \param this pointer to an object
8028 * \param klass klass of the object containing \p field
8029 * \param field the field to load
8030 * \param res a storage to store the result
8031 * \param error set on error
8032 * This method is called by the runtime on attempts to load fields of
8033 * transparent proxy objects. \p this points to such TP, \p klass is the class of
8034 * the object containing \p field. \p res is a storage location which can be
8035 * used to store the result.
8036 * \returns an address pointing to the value of field. On failure returns NULL and sets \p error.
8039 mono_load_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res, MonoError *error)
8041 MONO_REQ_GC_UNSAFE_MODE;
8043 static MonoMethod *getter = NULL;
8047 MonoDomain *domain = mono_domain_get ();
8048 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8049 MonoClass *field_class;
8050 MonoMethodMessage *msg;
8051 MonoArray *out_args;
8055 g_assert (mono_object_is_transparent_proxy (this_obj));
8056 g_assert (res != NULL);
8058 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8059 mono_field_get_value (tp->rp->unwrapped_server, field, res);
8064 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
8066 mono_error_set_not_supported (error, "Linked away.");
8071 field_class = mono_class_from_mono_type (field->type);
8073 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8074 return_val_if_nok (error, NULL);
8075 out_args = mono_array_new_checked (domain, mono_defaults.object_class, 1, error);
8076 return_val_if_nok (error, NULL);
8077 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, error);
8078 return_val_if_nok (error, NULL);
8079 mono_message_init (domain, msg, rm, out_args, error);
8080 return_val_if_nok (error, NULL);
8082 full_name = mono_type_get_full_name (klass);
8083 MonoString *full_name_str = mono_string_new_checked (domain, full_name, error);
8085 return_val_if_nok (error, NULL);
8086 mono_array_setref (msg->args, 0, full_name_str);
8087 MonoString *field_name = mono_string_new_checked (domain, mono_field_get_name (field), error);
8088 return_val_if_nok (error, NULL);
8089 mono_array_setref (msg->args, 1, field_name);
8091 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8092 return_val_if_nok (error, NULL);
8095 mono_error_set_exception_instance (error, (MonoException *)exc);
8099 if (mono_array_length (out_args) == 0)
8102 mono_gc_wbarrier_generic_store (res, mono_array_get (out_args, MonoObject *, 0));
8104 if (field_class->valuetype) {
8105 return ((char *)*res) + sizeof (MonoObject);
8111 * mono_load_remote_field_new:
8115 * Missing documentation.
8118 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
8122 MonoObject *result = mono_load_remote_field_new_checked (this_obj, klass, field, &error);
8123 mono_error_cleanup (&error);
8128 * mono_load_remote_field_new_checked:
8129 * \param this pointer to an object
8130 * \param klass klass of the object containing \p field
8131 * \param field the field to load
8132 * \param error set on error.
8133 * This method is called by the runtime on attempts to load fields of
8134 * transparent proxy objects. \p this points to such TP, \p klass is the class of
8135 * the object containing \p field.
8136 * \returns a freshly allocated object containing the value of the field. On failure returns NULL and sets \p error.
8139 mono_load_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoError *error)
8141 MONO_REQ_GC_UNSAFE_MODE;
8145 static MonoMethod *tp_load = NULL;
8147 g_assert (mono_object_is_transparent_proxy (this_obj));
8150 tp_load = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "LoadRemoteFieldNew", -1);
8152 mono_error_set_not_supported (error, "Linked away.");
8157 /* MonoType *type = mono_class_get_type (klass); */
8163 return mono_runtime_invoke_checked (tp_load, this_obj, args, error);
8167 * mono_store_remote_field:
8168 * \param this_obj pointer to an object
8169 * \param klass klass of the object containing \p field
8170 * \param field the field to load
8171 * \param val the value/object to store
8172 * This method is called by the runtime on attempts to store fields of
8173 * transparent proxy objects. \p this_obj points to such TP, \p klass is the class of
8174 * the object containing \p field. \p val is the new value to store in \p field.
8177 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
8180 (void) mono_store_remote_field_checked (this_obj, klass, field, val, &error);
8181 mono_error_cleanup (&error);
8185 * mono_store_remote_field_checked:
8186 * \param this_obj pointer to an object
8187 * \param klass klass of the object containing \p field
8188 * \param field the field to load
8189 * \param val the value/object to store
8190 * \param error set on error
8191 * This method is called by the runtime on attempts to store fields of
8192 * transparent proxy objects. \p this_obj points to such TP, \p klass is the class of
8193 * the object containing \p field. \p val is the new value to store in \p field.
8194 * \returns on success returns TRUE, on failure returns FALSE and sets \p error.
8197 mono_store_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val, MonoError *error)
8200 MONO_REQ_GC_UNSAFE_MODE;
8204 MonoDomain *domain = mono_domain_get ();
8205 MonoClass *field_class;
8208 g_assert (mono_object_is_transparent_proxy (this_obj));
8210 field_class = mono_class_from_mono_type (field->type);
8212 if (field_class->valuetype) {
8213 arg = mono_value_box_checked (domain, field_class, val, error);
8214 return_val_if_nok (error, FALSE);
8216 arg = *((MonoObject**)val);
8219 return mono_store_remote_field_new_checked (this_obj, klass, field, arg, error);
8223 * mono_store_remote_field_new:
8228 * Missing documentation
8231 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
8234 (void) mono_store_remote_field_new_checked (this_obj, klass, field, arg, &error);
8235 mono_error_cleanup (&error);
8239 * mono_store_remote_field_new_checked:
8245 * Missing documentation
8248 mono_store_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg, MonoError *error)
8250 MONO_REQ_GC_UNSAFE_MODE;
8252 static MonoMethod *tp_store = NULL;
8256 g_assert (mono_object_is_transparent_proxy (this_obj));
8259 tp_store = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "StoreRemoteField", -1);
8261 mono_error_set_not_supported (error, "Linked away.");
8271 mono_runtime_invoke_checked (tp_store, this_obj, args, error);
8272 return is_ok (error);
8277 * mono_create_ftnptr:
8279 * Given a function address, create a function descriptor for it.
8280 * This is only needed on some platforms.
8283 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
8285 return callbacks.create_ftnptr (domain, addr);
8289 * mono_get_addr_from_ftnptr:
8291 * Given a pointer to a function descriptor, return the function address.
8292 * This is only needed on some platforms.
8295 mono_get_addr_from_ftnptr (gpointer descr)
8297 return callbacks.get_addr_from_ftnptr (descr);
8301 * mono_string_chars:
8302 * \param s a \c MonoString
8303 * \returns a pointer to the UTF-16 characters stored in the \c MonoString
8306 mono_string_chars (MonoString *s)
8308 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
8314 * mono_string_length:
8315 * \param s MonoString
8316 * \returns the length in characters of the string
8319 mono_string_length (MonoString *s)
8321 MONO_REQ_GC_UNSAFE_MODE;
8327 * mono_string_handle_length:
8328 * \param s \c MonoString
8329 * \returns the length in characters of the string
8332 mono_string_handle_length (MonoStringHandle s)
8334 MONO_REQ_GC_UNSAFE_MODE;
8336 return MONO_HANDLE_GETVAL (s, length);
8341 * mono_array_length:
8342 * \param array a \c MonoArray*
8343 * \returns the total number of elements in the array. This works for
8344 * both vectors and multidimensional arrays.
8347 mono_array_length (MonoArray *array)
8349 MONO_REQ_GC_UNSAFE_MODE;
8351 return array->max_length;
8355 * mono_array_addr_with_size:
8356 * \param array a \c MonoArray*
8357 * \param size size of the array elements
8358 * \param idx index into the array
8359 * Use this function to obtain the address for the \p idx item on the
8360 * \p array containing elements of size \p size.
8362 * This method performs no bounds checking or type checking.
8363 * \returns the address of the \p idx element in the array.
8366 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
8368 MONO_REQ_GC_UNSAFE_MODE;
8370 return ((char*)(array)->vector) + size * idx;
8375 mono_glist_to_array (GList *list, MonoClass *eclass, MonoError *error)
8377 MonoDomain *domain = mono_domain_get ();
8385 len = g_list_length (list);
8386 res = mono_array_new_checked (domain, eclass, len, error);
8387 return_val_if_nok (error, NULL);
8389 for (i = 0; list; list = list->next, i++)
8390 mono_array_set (res, gpointer, i, list->data);
8397 * The following section is purely to declare prototypes and
8398 * document the API, as these C files are processed by our
8404 * \param array array to alter
8405 * \param element_type A C type name, this macro will use the sizeof(type) to determine the element size
8406 * \param index index into the array
8407 * \param value value to set
8408 * Value Type version: This sets the \p index's element of the \p array
8409 * with elements of size sizeof(type) to the provided \p value.
8411 * This macro does not attempt to perform type checking or bounds checking.
8413 * Use this to set value types in a \c MonoArray.
8415 void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
8420 * mono_array_setref:
8421 * \param array array to alter
8422 * \param index index into the array
8423 * \param value value to set
8424 * Reference Type version. This sets the \p index's element of the
8425 * \p array with elements of size sizeof(type) to the provided \p value.
8427 * This macro does not attempt to perform type checking or bounds checking.
8429 * Use this to reference types in a \c MonoArray.
8431 void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
8437 * \param array array on which to operate on
8438 * \param element_type C element type (example: \c MonoString*, \c int, \c MonoObject*)
8439 * \param index index into the array
8441 * Use this macro to retrieve the \p index element of an \p array and
8442 * extract the value assuming that the elements of the array match
8443 * the provided type value.
8445 * This method can be used with both arrays holding value types and
8446 * reference types. For reference types, the \p type parameter should
8447 * be a \c MonoObject* or any subclass of it, like \c MonoString*.
8449 * This macro does not attempt to perform type checking or bounds checking.
8451 * \returns The element at the \p index position in the \p array.
8453 Type mono_array_get (MonoArray *array, Type element_type, uintptr_t index)