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>
52 #include <mono/utils/unlocked.h>
55 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error);
58 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error);
61 free_main_args (void);
64 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error);
67 array_full_copy_unchecked_size (MonoArray *src, MonoArray *dest, MonoClass *klass, uintptr_t size);
70 class_get_virtual_method (MonoClass *klass, MonoMethod *method, gboolean is_proxy, MonoError *error);
72 /* Class lazy loading functions */
73 static GENERATE_GET_CLASS_WITH_CACHE (pointer, "System.Reflection", "Pointer")
74 static GENERATE_GET_CLASS_WITH_CACHE (remoting_services, "System.Runtime.Remoting", "RemotingServices")
75 static GENERATE_GET_CLASS_WITH_CACHE (unhandled_exception_event_args, "System", "UnhandledExceptionEventArgs")
76 static GENERATE_GET_CLASS_WITH_CACHE (sta_thread_attribute, "System", "STAThreadAttribute")
77 static GENERATE_GET_CLASS_WITH_CACHE (activation_services, "System.Runtime.Remoting.Activation", "ActivationServices")
80 #define ldstr_lock() mono_os_mutex_lock (&ldstr_section)
81 #define ldstr_unlock() mono_os_mutex_unlock (&ldstr_section)
82 static mono_mutex_t ldstr_section;
86 * mono_runtime_object_init:
87 * \param this_obj the object to initialize
88 * This function calls the zero-argument constructor (which must
89 * exist) for the given object.
92 mono_runtime_object_init (MonoObject *this_obj)
95 mono_runtime_object_init_checked (this_obj, &error);
96 mono_error_assert_ok (&error);
100 * mono_runtime_object_init_checked:
101 * \param this_obj the object to initialize
102 * \param error set on error.
103 * This function calls the zero-argument constructor (which must
104 * exist) for the given object and returns TRUE on success, or FALSE
105 * on error and sets \p error.
108 mono_runtime_object_init_checked (MonoObject *this_obj, MonoError *error)
110 MONO_REQ_GC_UNSAFE_MODE;
112 MonoMethod *method = NULL;
113 MonoClass *klass = this_obj->vtable->klass;
116 method = mono_class_get_method_from_name (klass, ".ctor", 0);
118 g_error ("Could not lookup zero argument constructor for class %s", mono_type_get_full_name (klass));
120 if (method->klass->valuetype)
121 this_obj = (MonoObject *)mono_object_unbox (this_obj);
123 mono_runtime_invoke_checked (method, this_obj, NULL, error);
124 return is_ok (error);
127 /* The pseudo algorithm for type initialization from the spec
128 Note it doesn't say anything about domains - only threads.
130 2. If the type is initialized you are done.
131 2.1. If the type is not yet initialized, try to take an
133 2.2. If successful, record this thread as responsible for
134 initializing the type and proceed to step 2.3.
135 2.2.1. If not, see whether this thread or any thread
136 waiting for this thread to complete already holds the lock.
137 2.2.2. If so, return since blocking would create a deadlock. This thread
138 will now see an incompletely initialized state for the type,
139 but no deadlock will arise.
140 2.2.3 If not, block until the type is initialized then return.
141 2.3 Initialize the parent type and then all interfaces implemented
143 2.4 Execute the type initialization code for this type.
144 2.5 Mark the type as initialized, release the initialization lock,
145 awaken any threads waiting for this type to be initialized,
152 MonoNativeThreadId initializing_tid;
153 guint32 waiting_count;
156 /* condvar used to wait for 'done' becoming TRUE */
158 } TypeInitializationLock;
160 /* for locking access to type_initialization_hash and blocked_thread_hash */
161 static MonoCoopMutex type_initialization_section;
164 mono_type_initialization_lock (void)
166 /* The critical sections protected by this lock in mono_runtime_class_init_full () can block */
167 mono_coop_mutex_lock (&type_initialization_section);
171 mono_type_initialization_unlock (void)
173 mono_coop_mutex_unlock (&type_initialization_section);
177 mono_type_init_lock (TypeInitializationLock *lock)
179 MONO_REQ_GC_NEUTRAL_MODE;
181 mono_coop_mutex_lock (&lock->mutex);
185 mono_type_init_unlock (TypeInitializationLock *lock)
187 mono_coop_mutex_unlock (&lock->mutex);
190 /* from vtable to lock */
191 static GHashTable *type_initialization_hash;
193 /* from thread id to thread id being waited on */
194 static GHashTable *blocked_thread_hash;
197 static MonoThread *main_thread;
199 /* Functions supplied by the runtime */
200 static MonoRuntimeCallbacks callbacks;
203 * mono_thread_set_main:
204 * \param thread thread to set as the main thread
205 * This function can be used to instruct the runtime to treat \p thread
206 * as the main thread, ie, the thread that would normally execute the \c Main
207 * method. This basically means that at the end of \p thread, the runtime will
208 * wait for the existing foreground threads to quit and other such details.
211 mono_thread_set_main (MonoThread *thread)
213 MONO_REQ_GC_UNSAFE_MODE;
215 static gboolean registered = FALSE;
218 MONO_GC_REGISTER_ROOT_SINGLE (main_thread, MONO_ROOT_SOURCE_THREADING, "main thread object");
222 main_thread = thread;
226 * mono_thread_get_main:
229 mono_thread_get_main (void)
231 MONO_REQ_GC_UNSAFE_MODE;
237 mono_type_initialization_init (void)
239 mono_coop_mutex_init_recursive (&type_initialization_section);
240 type_initialization_hash = g_hash_table_new (NULL, NULL);
241 blocked_thread_hash = g_hash_table_new (NULL, NULL);
242 mono_os_mutex_init_recursive (&ldstr_section);
243 mono_register_jit_icall (ves_icall_string_alloc, "ves_icall_string_alloc", mono_create_icall_signature ("object int"), FALSE);
247 mono_type_initialization_cleanup (void)
250 /* This is causing race conditions with
251 * mono_release_type_locks
253 mono_coop_mutex_destroy (&type_initialization_section);
254 g_hash_table_destroy (type_initialization_hash);
255 type_initialization_hash = NULL;
257 mono_os_mutex_destroy (&ldstr_section);
258 g_hash_table_destroy (blocked_thread_hash);
259 blocked_thread_hash = NULL;
265 * get_type_init_exception_for_vtable:
267 * Return the stored type initialization exception for VTABLE.
269 static MonoException*
270 get_type_init_exception_for_vtable (MonoVTable *vtable)
272 MONO_REQ_GC_UNSAFE_MODE;
275 MonoDomain *domain = vtable->domain;
276 MonoClass *klass = vtable->klass;
280 if (!vtable->init_failed)
281 g_error ("Trying to get the init exception for a non-failed vtable of class %s", mono_type_get_full_name (klass));
284 * If the initializing thread was rudely aborted, the exception is not stored
288 mono_domain_lock (domain);
289 if (domain->type_init_exception_hash)
290 ex = (MonoException *)mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
291 mono_domain_unlock (domain);
294 if (klass->name_space && *klass->name_space)
295 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
297 full_name = g_strdup (klass->name);
298 ex = mono_get_exception_type_initialization_checked (full_name, NULL, &error);
300 return_val_if_nok (&error, NULL);
307 * mono_runtime_class_init:
308 * \param vtable vtable that needs to be initialized
309 * This routine calls the class constructor for \p vtable.
312 mono_runtime_class_init (MonoVTable *vtable)
314 MONO_REQ_GC_UNSAFE_MODE;
317 mono_runtime_class_init_full (vtable, &error);
318 mono_error_assert_ok (&error);
322 * Returns TRUE if the lock was freed.
323 * LOCKING: Caller should hold type_initialization_lock.
326 unref_type_lock (TypeInitializationLock *lock)
328 --lock->waiting_count;
329 if (lock->waiting_count == 0) {
330 mono_coop_mutex_destroy (&lock->mutex);
331 mono_coop_cond_destroy (&lock->cond);
340 * mono_runtime_class_init_full:
341 * \param vtable that neeeds to be initialized
342 * \param error set on error
343 * \returns TRUE if class constructor \c .cctor has been initialized successfully, or FALSE otherwise and sets \p error.
346 mono_runtime_class_init_full (MonoVTable *vtable, MonoError *error)
348 MONO_REQ_GC_UNSAFE_MODE;
350 MonoMethod *method = NULL;
353 MonoDomain *domain = vtable->domain;
354 TypeInitializationLock *lock;
355 MonoNativeThreadId tid;
356 int do_initialization = 0;
357 MonoDomain *last_domain = NULL;
358 gboolean pending_tae = FALSE;
362 if (vtable->initialized)
365 klass = vtable->klass;
367 if (!klass->image->checked_module_cctor) {
368 mono_image_check_for_module_cctor (klass->image);
369 if (klass->image->has_module_cctor) {
370 MonoClass *module_klass;
371 MonoVTable *module_vtable;
373 module_klass = mono_class_get_checked (klass->image, MONO_TOKEN_TYPE_DEF | 1, error);
378 module_vtable = mono_class_vtable_full (vtable->domain, module_klass, error);
381 if (!mono_runtime_class_init_full (module_vtable, error))
385 method = mono_class_get_cctor (klass);
387 vtable->initialized = 1;
391 tid = mono_native_thread_id_get ();
394 * Due some preprocessing inside a global lock. If we are the first thread
395 * trying to initialize this class, create a separate lock+cond var, and
396 * acquire it before leaving the global lock. The other threads will wait
400 mono_type_initialization_lock ();
401 /* double check... */
402 if (vtable->initialized) {
403 mono_type_initialization_unlock ();
406 if (vtable->init_failed) {
407 mono_type_initialization_unlock ();
409 /* The type initialization already failed once, rethrow the same exception */
410 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
413 lock = (TypeInitializationLock *)g_hash_table_lookup (type_initialization_hash, vtable);
415 /* This thread will get to do the initialization */
416 if (mono_domain_get () != domain) {
417 /* Transfer into the target domain */
418 last_domain = mono_domain_get ();
419 if (!mono_domain_set (domain, FALSE)) {
420 vtable->initialized = 1;
421 mono_type_initialization_unlock ();
422 mono_error_set_exception_instance (error, mono_get_exception_appdomain_unloaded ());
426 lock = (TypeInitializationLock *)g_malloc0 (sizeof (TypeInitializationLock));
427 mono_coop_mutex_init_recursive (&lock->mutex);
428 mono_coop_cond_init (&lock->cond);
429 lock->initializing_tid = tid;
430 lock->waiting_count = 1;
432 g_hash_table_insert (type_initialization_hash, vtable, lock);
433 do_initialization = 1;
436 TypeInitializationLock *pending_lock;
438 if (mono_native_thread_id_equals (lock->initializing_tid, tid)) {
439 mono_type_initialization_unlock ();
442 /* see if the thread doing the initialization is already blocked on this thread */
443 gboolean is_blocked = TRUE;
444 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (lock->initializing_tid));
445 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
446 if (mono_native_thread_id_equals (pending_lock->initializing_tid, tid)) {
447 if (!pending_lock->done) {
448 mono_type_initialization_unlock ();
451 /* the thread doing the initialization is blocked on this thread,
452 but on a lock that has already been freed. It just hasn't got
458 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (pending_lock->initializing_tid));
460 ++lock->waiting_count;
461 /* record the fact that we are waiting on the initializing thread */
463 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
465 mono_type_initialization_unlock ();
467 if (do_initialization) {
468 MonoException *exc = NULL;
470 /* We are holding the per-vtable lock, do the actual initialization */
472 mono_threads_begin_abort_protected_block ();
473 mono_runtime_try_invoke (method, NULL, NULL, (MonoObject**) &exc, error);
474 mono_threads_end_abort_protected_block ();
476 //exception extracted, error will be set to the right value later
477 if (exc == NULL && !mono_error_ok (error))//invoking failed but exc was not set
478 exc = mono_error_convert_to_exception (error);
480 mono_error_cleanup (error);
484 /* If the initialization failed, mark the class as unusable. */
485 /* Avoid infinite loops */
487 (klass->image == mono_defaults.corlib &&
488 !strcmp (klass->name_space, "System") &&
489 !strcmp (klass->name, "TypeInitializationException")))) {
490 vtable->init_failed = 1;
492 if (klass->name_space && *klass->name_space)
493 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
495 full_name = g_strdup (klass->name);
497 MonoException *exc_to_throw = mono_get_exception_type_initialization_checked (full_name, exc, error);
500 mono_error_assert_ok (error); //We can't recover from this, no way to fail a type we can't alloc a failure.
503 * Store the exception object so it could be thrown on subsequent
506 mono_domain_lock (domain);
507 if (!domain->type_init_exception_hash)
508 domain->type_init_exception_hash = mono_g_hash_table_new_type (mono_aligned_addr_hash, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_DOMAIN, "type initialization exceptions table");
509 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
510 mono_domain_unlock (domain);
514 mono_domain_set (last_domain, TRUE);
516 /* Signal to the other threads that we are done */
517 mono_type_init_lock (lock);
519 mono_coop_cond_broadcast (&lock->cond);
520 mono_type_init_unlock (lock);
523 * This can happen if the cctor self-aborts. We need to reactivate tae
524 * (next interruption checkpoint will throw it) and make sure we won't
525 * throw tie for the type.
527 if (exc && mono_object_class (exc) == mono_defaults.threadabortexception_class) {
529 mono_thread_resume_interruption (FALSE);
532 /* this just blocks until the initializing thread is done */
533 mono_type_init_lock (lock);
535 mono_coop_cond_wait (&lock->cond, &lock->mutex);
536 mono_type_init_unlock (lock);
539 /* Do cleanup and setting vtable->initialized inside the global lock again */
540 mono_type_initialization_lock ();
541 if (!do_initialization)
542 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
543 gboolean deleted = unref_type_lock (lock);
545 g_hash_table_remove (type_initialization_hash, vtable);
546 /* Have to set this here since we check it inside the global lock */
547 if (do_initialization && !vtable->init_failed)
548 vtable->initialized = 1;
549 mono_type_initialization_unlock ();
551 /* If vtable init fails because of TAE, we don't throw TIE, only the TAE */
552 if (vtable->init_failed && !pending_tae) {
553 /* Either we were the initializing thread or we waited for the initialization */
554 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
561 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
563 MONO_REQ_GC_NEUTRAL_MODE;
565 MonoVTable *vtable = (MonoVTable*)key;
567 TypeInitializationLock *lock = (TypeInitializationLock*) value;
568 if (mono_native_thread_id_equals (lock->initializing_tid, MONO_UINT_TO_NATIVE_THREAD_ID (GPOINTER_TO_UINT (user))) && !lock->done) {
571 * Have to set this since it cannot be set by the normal code in
572 * mono_runtime_class_init (). In this case, the exception object is not stored,
573 * and get_type_init_exception_for_class () needs to be aware of this.
575 mono_type_init_lock (lock);
576 vtable->init_failed = 1;
577 mono_coop_cond_broadcast (&lock->cond);
578 mono_type_init_unlock (lock);
579 gboolean deleted = unref_type_lock (lock);
587 mono_release_type_locks (MonoInternalThread *thread)
589 MONO_REQ_GC_UNSAFE_MODE;
591 mono_type_initialization_lock ();
592 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, GUINT_TO_POINTER (thread->tid));
593 mono_type_initialization_unlock ();
596 #ifndef DISABLE_REMOTING
599 create_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error)
601 if (!callbacks.create_remoting_trampoline)
602 g_error ("remoting not installed");
603 return callbacks.create_remoting_trampoline (domain, method, target, error);
608 static MonoImtTrampolineBuilder imt_trampoline_builder;
609 static gboolean always_build_imt_trampolines;
611 #if (MONO_IMT_SIZE > 32)
612 #error "MONO_IMT_SIZE cannot be larger than 32"
616 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
618 memcpy (&callbacks, cbs, sizeof (*cbs));
621 MonoRuntimeCallbacks*
622 mono_get_runtime_callbacks (void)
628 mono_install_imt_trampoline_builder (MonoImtTrampolineBuilder func)
630 imt_trampoline_builder = func;
634 mono_set_always_build_imt_trampolines (gboolean value)
636 always_build_imt_trampolines = value;
640 * mono_compile_method:
641 * \param method The method to compile.
642 * This JIT-compiles the method, and returns the pointer to the native code
646 mono_compile_method (MonoMethod *method)
649 gpointer result = mono_compile_method_checked (method, &error);
650 mono_error_cleanup (&error);
655 * mono_compile_method_checked:
656 * \param method The method to compile.
657 * \param error set on error.
658 * This JIT-compiles the method, and returns the pointer to the native code
659 * produced. On failure returns NULL and sets \p error.
662 mono_compile_method_checked (MonoMethod *method, MonoError *error)
666 MONO_REQ_GC_NEUTRAL_MODE
670 g_assert (callbacks.compile_method);
671 res = callbacks.compile_method (method, error);
676 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper, MonoError *error)
680 MONO_REQ_GC_NEUTRAL_MODE;
683 res = callbacks.create_jump_trampoline (domain, method, add_sync_wrapper, error);
688 mono_runtime_create_delegate_trampoline (MonoClass *klass)
690 MONO_REQ_GC_NEUTRAL_MODE
692 g_assert (callbacks.create_delegate_trampoline);
693 return callbacks.create_delegate_trampoline (mono_domain_get (), klass);
697 * mono_runtime_free_method:
698 * \param domain domain where the method is hosted
699 * \param method method to release
700 * This routine is invoked to free the resources associated with
701 * a method that has been JIT compiled. This is used to discard
702 * methods that were used only temporarily (for example, used in marshalling)
705 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
707 MONO_REQ_GC_NEUTRAL_MODE
709 if (callbacks.free_method)
710 callbacks.free_method (domain, method);
712 mono_method_clear_object (domain, method);
714 mono_free_method (method);
718 * The vtables in the root appdomain are assumed to be reachable by other
719 * roots, and we don't use typed allocation in the other domains.
722 /* The sync block is no longer a GC pointer */
723 #define GC_HEADER_BITMAP (0)
725 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
728 compute_class_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
730 MONO_REQ_GC_NEUTRAL_MODE;
732 MonoClassField *field;
738 max_size = mono_class_data_size (klass) / sizeof (gpointer);
740 max_size = klass->instance_size / sizeof (gpointer);
741 if (max_size > size) {
742 g_assert (offset <= 0);
743 bitmap = (gsize *)g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
747 /* An Ephemeron cannot be marked by sgen */
748 if (mono_gc_is_moving () && !static_fields && klass->image == mono_defaults.corlib && !strcmp ("Ephemeron", klass->name)) {
750 memset (bitmap, 0, size / 8);
754 for (p = klass; p != NULL; p = p->parent) {
755 gpointer iter = NULL;
756 while ((field = mono_class_get_fields (p, &iter))) {
760 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
762 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
765 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
768 /* FIXME: should not happen, flag as type load error */
769 if (field->type->byref)
772 if (static_fields && field->offset == -1)
776 pos = field->offset / sizeof (gpointer);
779 type = mono_type_get_underlying_type (field->type);
780 switch (type->type) {
784 case MONO_TYPE_FNPTR:
786 case MONO_TYPE_STRING:
787 case MONO_TYPE_SZARRAY:
788 case MONO_TYPE_CLASS:
789 case MONO_TYPE_OBJECT:
790 case MONO_TYPE_ARRAY:
791 g_assert ((field->offset % sizeof(gpointer)) == 0);
793 g_assert (pos < size || pos <= max_size);
794 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
795 *max_set = MAX (*max_set, pos);
797 case MONO_TYPE_GENERICINST:
798 if (!mono_type_generic_inst_is_valuetype (type)) {
799 g_assert ((field->offset % sizeof(gpointer)) == 0);
801 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
802 *max_set = MAX (*max_set, pos);
807 case MONO_TYPE_VALUETYPE: {
808 MonoClass *fclass = mono_class_from_mono_type (field->type);
809 if (fclass->has_references) {
810 /* remove the object header */
811 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
825 case MONO_TYPE_BOOLEAN:
829 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
840 * mono_class_compute_bitmap:
842 * Mono internal function to compute a bitmap of reference fields in a class.
845 mono_class_compute_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
847 MONO_REQ_GC_NEUTRAL_MODE;
849 return compute_class_bitmap (klass, bitmap, size, offset, max_set, static_fields);
854 * similar to the above, but sets the bits in the bitmap for any non-ref field
855 * and ignores static fields
858 compute_class_non_ref_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset)
860 MonoClassField *field;
865 max_size = class->instance_size / sizeof (gpointer);
866 if (max_size >= size) {
867 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
870 for (p = class; p != NULL; p = p->parent) {
871 gpointer iter = NULL;
872 while ((field = mono_class_get_fields (p, &iter))) {
875 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
877 /* FIXME: should not happen, flag as type load error */
878 if (field->type->byref)
881 pos = field->offset / sizeof (gpointer);
884 type = mono_type_get_underlying_type (field->type);
885 switch (type->type) {
886 #if SIZEOF_VOID_P == 8
890 case MONO_TYPE_FNPTR:
895 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
896 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
897 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
900 #if SIZEOF_VOID_P == 4
904 case MONO_TYPE_FNPTR:
909 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
910 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
911 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
917 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
918 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
919 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
922 case MONO_TYPE_BOOLEAN:
925 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
927 case MONO_TYPE_STRING:
928 case MONO_TYPE_SZARRAY:
929 case MONO_TYPE_CLASS:
930 case MONO_TYPE_OBJECT:
931 case MONO_TYPE_ARRAY:
933 case MONO_TYPE_GENERICINST:
934 if (!mono_type_generic_inst_is_valuetype (type)) {
939 case MONO_TYPE_VALUETYPE: {
940 MonoClass *fclass = mono_class_from_mono_type (field->type);
941 /* remove the object header */
942 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
946 g_assert_not_reached ();
955 * mono_class_insecure_overlapping:
956 * check if a class with explicit layout has references and non-references
957 * fields overlapping.
959 * Returns: TRUE if it is insecure to load the type.
962 mono_class_insecure_overlapping (MonoClass *klass)
966 gsize default_bitmap [4] = {0};
968 gsize default_nrbitmap [4] = {0};
969 int i, insecure = FALSE;
972 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
973 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
975 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
976 int idx = i % (sizeof (bitmap [0]) * 8);
977 if (bitmap [idx] & nrbitmap [idx]) {
982 if (bitmap != default_bitmap)
984 if (nrbitmap != default_nrbitmap)
987 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
995 ves_icall_string_alloc (int length)
998 MonoString *str = mono_string_new_size_checked (mono_domain_get (), length, &error);
999 mono_error_set_pending_exception (&error);
1004 /* LOCKING: Acquires the loader lock */
1006 mono_class_compute_gc_descriptor (MonoClass *klass)
1008 MONO_REQ_GC_NEUTRAL_MODE;
1012 gsize default_bitmap [4] = {0};
1013 MonoGCDescriptor gc_descr;
1016 mono_class_init (klass);
1018 if (klass->gc_descr_inited)
1021 bitmap = default_bitmap;
1022 if (klass == mono_defaults.string_class) {
1023 gc_descr = mono_gc_make_descr_for_string (bitmap, 2);
1024 } else if (klass->rank) {
1025 mono_class_compute_gc_descriptor (klass->element_class);
1026 if (MONO_TYPE_IS_REFERENCE (&klass->element_class->byval_arg)) {
1028 gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
1029 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1030 class->name_space, class->name);*/
1032 /* remove the object header */
1033 bitmap = compute_class_bitmap (klass->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
1034 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));
1035 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1036 class->name_space, class->name);*/
1037 if (bitmap != default_bitmap)
1041 /*static int count = 0;
1044 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1045 gc_descr = mono_gc_make_descr_for_object (bitmap, max_set + 1, klass->instance_size);
1047 if (class->gc_descr == MONO_GC_DESCRIPTOR_NULL)
1048 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
1050 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
1051 if (bitmap != default_bitmap)
1055 /* Publish the data */
1056 mono_loader_lock ();
1057 klass->gc_descr = gc_descr;
1058 mono_memory_barrier ();
1059 klass->gc_descr_inited = TRUE;
1060 mono_loader_unlock ();
1064 * field_is_special_static:
1065 * @fklass: The MonoClass to look up.
1066 * @field: The MonoClassField describing the field.
1068 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1069 * SPECIAL_STATIC_NONE otherwise.
1072 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1074 MONO_REQ_GC_NEUTRAL_MODE;
1077 MonoCustomAttrInfo *ainfo;
1079 ainfo = mono_custom_attrs_from_field_checked (fklass, field, &error);
1080 mono_error_cleanup (&error); /* FIXME don't swallow the error? */
1083 for (i = 0; i < ainfo->num_attrs; ++i) {
1084 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1085 if (klass->image == mono_defaults.corlib) {
1086 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1087 mono_custom_attrs_free (ainfo);
1088 return SPECIAL_STATIC_THREAD;
1090 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1091 mono_custom_attrs_free (ainfo);
1092 return SPECIAL_STATIC_CONTEXT;
1096 mono_custom_attrs_free (ainfo);
1097 return SPECIAL_STATIC_NONE;
1100 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1101 #define mix(a,b,c) { \
1102 a -= c; a ^= rot(c, 4); c += b; \
1103 b -= a; b ^= rot(a, 6); a += c; \
1104 c -= b; c ^= rot(b, 8); b += a; \
1105 a -= c; a ^= rot(c,16); c += b; \
1106 b -= a; b ^= rot(a,19); a += c; \
1107 c -= b; c ^= rot(b, 4); b += a; \
1109 #define final(a,b,c) { \
1110 c ^= b; c -= rot(b,14); \
1111 a ^= c; a -= rot(c,11); \
1112 b ^= a; b -= rot(a,25); \
1113 c ^= b; c -= rot(b,16); \
1114 a ^= c; a -= rot(c,4); \
1115 b ^= a; b -= rot(a,14); \
1116 c ^= b; c -= rot(b,24); \
1120 * mono_method_get_imt_slot:
1122 * The IMT slot is embedded into AOTed code, so this must return the same value
1123 * for the same method across all executions. This means:
1124 * - pointers shouldn't be used as hash values.
1125 * - mono_metadata_str_hash () should be used for hashing strings.
1128 mono_method_get_imt_slot (MonoMethod *method)
1130 MONO_REQ_GC_NEUTRAL_MODE;
1132 MonoMethodSignature *sig;
1134 guint32 *hashes_start, *hashes;
1138 /* This can be used to stress tests the collision code */
1142 * We do this to simplify generic sharing. It will hurt
1143 * performance in cases where a class implements two different
1144 * instantiations of the same generic interface.
1145 * The code in build_imt_slots () depends on this.
1147 if (method->is_inflated)
1148 method = ((MonoMethodInflated*)method)->declaring;
1150 sig = mono_method_signature (method);
1151 hashes_count = sig->param_count + 4;
1152 hashes_start = (guint32 *)g_malloc (hashes_count * sizeof (guint32));
1153 hashes = hashes_start;
1155 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1156 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1157 method->klass->name_space, method->klass->name, method->name);
1160 /* Initialize hashes */
1161 hashes [0] = mono_metadata_str_hash (method->klass->name);
1162 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1163 hashes [2] = mono_metadata_str_hash (method->name);
1164 hashes [3] = mono_metadata_type_hash (sig->ret);
1165 for (i = 0; i < sig->param_count; i++) {
1166 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1169 /* Setup internal state */
1170 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1172 /* Handle most of the hashes */
1173 while (hashes_count > 3) {
1182 /* Handle the last 3 hashes (all the case statements fall through) */
1183 switch (hashes_count) {
1184 case 3 : c += hashes [2];
1185 case 2 : b += hashes [1];
1186 case 1 : a += hashes [0];
1188 case 0: /* nothing left to add */
1192 g_free (hashes_start);
1193 /* Report the result */
1194 return c % MONO_IMT_SIZE;
1203 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1204 MONO_REQ_GC_NEUTRAL_MODE;
1206 guint32 imt_slot = mono_method_get_imt_slot (method);
1207 MonoImtBuilderEntry *entry;
1209 if (slot_num >= 0 && imt_slot != slot_num) {
1210 /* we build just a single imt slot and this is not it */
1214 entry = (MonoImtBuilderEntry *)g_malloc0 (sizeof (MonoImtBuilderEntry));
1215 entry->key = method;
1216 entry->value.vtable_slot = vtable_slot;
1217 entry->next = imt_builder [imt_slot];
1218 if (imt_builder [imt_slot] != NULL) {
1219 entry->children = imt_builder [imt_slot]->children + 1;
1220 if (entry->children == 1) {
1221 UnlockedIncrement (&mono_stats.imt_slots_with_collisions);
1222 *imt_collisions_bitmap |= (1 << imt_slot);
1225 entry->children = 0;
1226 UnlockedIncrement (&mono_stats.imt_used_slots);
1228 imt_builder [imt_slot] = entry;
1231 char *method_name = mono_method_full_name (method, TRUE);
1232 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1233 method, method_name, imt_slot, vtable_slot, entry->children);
1234 g_free (method_name);
1241 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1243 MonoMethod *method = e->key;
1244 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1248 method->klass->name_space,
1249 method->klass->name,
1252 printf (" * %s: NULL\n", message);
1258 compare_imt_builder_entries (const void *p1, const void *p2) {
1259 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1260 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1262 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1266 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1268 MONO_REQ_GC_NEUTRAL_MODE;
1270 int count = end - start;
1271 int chunk_start = out_array->len;
1274 for (i = start; i < end; ++i) {
1275 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1276 item->key = sorted_array [i]->key;
1277 item->value = sorted_array [i]->value;
1278 item->has_target_code = sorted_array [i]->has_target_code;
1279 item->is_equals = TRUE;
1281 item->check_target_idx = out_array->len + 1;
1283 item->check_target_idx = 0;
1284 g_ptr_array_add (out_array, item);
1287 int middle = start + count / 2;
1288 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1290 item->key = sorted_array [middle]->key;
1291 item->is_equals = FALSE;
1292 g_ptr_array_add (out_array, item);
1293 imt_emit_ir (sorted_array, start, middle, out_array);
1294 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1300 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1301 MONO_REQ_GC_NEUTRAL_MODE;
1303 int number_of_entries = entries->children + 1;
1304 MonoImtBuilderEntry **sorted_array = (MonoImtBuilderEntry **)g_malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1305 GPtrArray *result = g_ptr_array_new ();
1306 MonoImtBuilderEntry *current_entry;
1309 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1310 sorted_array [i] = current_entry;
1312 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1314 /*for (i = 0; i < number_of_entries; i++) {
1315 print_imt_entry (" sorted array:", sorted_array [i], i);
1318 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1320 g_free (sorted_array);
1325 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1327 MONO_REQ_GC_NEUTRAL_MODE;
1329 if (imt_builder_entry != NULL) {
1330 if (imt_builder_entry->children == 0 && !fail_tramp && !always_build_imt_trampolines) {
1331 /* No collision, return the vtable slot contents */
1332 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1334 /* Collision, build the trampoline */
1335 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1338 result = imt_trampoline_builder (vtable, domain,
1339 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1340 for (i = 0; i < imt_ir->len; ++i)
1341 g_free (g_ptr_array_index (imt_ir, i));
1342 g_ptr_array_free (imt_ir, TRUE);
1354 static MonoImtBuilderEntry*
1355 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1358 * LOCKING: requires the loader and domain locks.
1362 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1364 MONO_REQ_GC_NEUTRAL_MODE;
1368 guint32 imt_collisions_bitmap = 0;
1369 MonoImtBuilderEntry **imt_builder = (MonoImtBuilderEntry **)g_calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1370 int method_count = 0;
1371 gboolean record_method_count_for_max_collisions = FALSE;
1372 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1375 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1377 for (i = 0; i < klass->interface_offsets_count; ++i) {
1378 MonoClass *iface = klass->interfaces_packed [i];
1379 int interface_offset = klass->interface_offsets_packed [i];
1380 int method_slot_in_interface, vt_slot;
1382 if (mono_class_has_variant_generic_params (iface))
1383 has_variant_iface = TRUE;
1385 mono_class_setup_methods (iface);
1386 vt_slot = interface_offset;
1387 int mcount = mono_class_get_method_count (iface);
1388 for (method_slot_in_interface = 0; method_slot_in_interface < mcount; method_slot_in_interface++) {
1391 if (slot_num >= 0 && mono_class_is_ginst (iface)) {
1393 * The imt slot of the method is the same as for its declaring method,
1394 * see the comment in mono_method_get_imt_slot (), so we can
1395 * avoid inflating methods which will be discarded by
1396 * add_imt_builder_entry anyway.
1398 method = mono_class_get_method_by_index (mono_class_get_generic_class (iface)->container_class, method_slot_in_interface);
1399 if (mono_method_get_imt_slot (method) != slot_num) {
1404 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1405 if (method->is_generic) {
1406 has_generic_virtual = TRUE;
1411 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1412 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1417 if (extra_interfaces) {
1418 int interface_offset = klass->vtable_size;
1420 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1421 MonoClass* iface = (MonoClass *)list_item->data;
1422 int method_slot_in_interface;
1423 int mcount = mono_class_get_method_count (iface);
1424 for (method_slot_in_interface = 0; method_slot_in_interface < mcount; method_slot_in_interface++) {
1425 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1427 if (method->is_generic)
1428 has_generic_virtual = TRUE;
1429 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1431 interface_offset += mcount;
1434 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1435 /* overwrite the imt slot only if we're building all the entries or if
1436 * we're building this specific one
1438 if (slot_num < 0 || i == slot_num) {
1439 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1442 if (imt_builder [i]) {
1443 MonoImtBuilderEntry *entry;
1445 /* Link entries with imt_builder [i] */
1446 for (entry = entries; entry->next; entry = entry->next) {
1448 MonoMethod *method = (MonoMethod*)entry->key;
1449 char *method_name = mono_method_full_name (method, TRUE);
1450 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1451 g_free (method_name);
1454 entry->next = imt_builder [i];
1455 entries->children += imt_builder [i]->children + 1;
1457 imt_builder [i] = entries;
1460 if (has_generic_virtual || has_variant_iface) {
1462 * There might be collisions later when the the trampoline is expanded.
1464 imt_collisions_bitmap |= (1 << i);
1467 * The IMT trampoline might be called with an instance of one of the
1468 * generic virtual methods, so has to fallback to the IMT trampoline.
1470 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline (vt, i));
1472 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1475 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1479 if (imt_builder [i] != NULL) {
1480 int methods_in_slot = imt_builder [i]->children + 1;
1481 if (methods_in_slot > UnlockedRead (&mono_stats.imt_max_collisions_in_slot)) {
1482 UnlockedWrite (&mono_stats.imt_max_collisions_in_slot, methods_in_slot);
1483 record_method_count_for_max_collisions = TRUE;
1485 method_count += methods_in_slot;
1489 UnlockedAdd (&mono_stats.imt_number_of_methods, method_count);
1490 if (record_method_count_for_max_collisions) {
1491 UnlockedWrite (&mono_stats.imt_method_count_when_max_collisions, method_count);
1494 for (i = 0; i < MONO_IMT_SIZE; i++) {
1495 MonoImtBuilderEntry* entry = imt_builder [i];
1496 while (entry != NULL) {
1497 MonoImtBuilderEntry* next = entry->next;
1502 g_free (imt_builder);
1503 /* we OR the bitmap since we may build just a single imt slot at a time */
1504 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1508 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1509 MONO_REQ_GC_NEUTRAL_MODE;
1511 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1515 * mono_vtable_build_imt_slot:
1516 * \param vtable virtual object table struct
1517 * \param imt_slot slot in the IMT table
1518 * Fill the given \p imt_slot in the IMT table of \p vtable with
1519 * a trampoline or a trampoline for the case of collisions.
1520 * This is part of the internal mono API.
1521 * LOCKING: Take the domain lock.
1524 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1526 MONO_REQ_GC_NEUTRAL_MODE;
1528 gpointer *imt = (gpointer*)vtable;
1529 imt -= MONO_IMT_SIZE;
1530 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1532 /* no support for extra interfaces: the proxy objects will need
1533 * to build the complete IMT
1534 * Update and heck needs to ahppen inside the proper domain lock, as all
1535 * the changes made to a MonoVTable.
1537 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1538 mono_domain_lock (vtable->domain);
1539 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1540 if (!callbacks.imt_entry_inited (vtable, imt_slot))
1541 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1542 mono_domain_unlock (vtable->domain);
1543 mono_loader_unlock ();
1546 #define THUNK_THRESHOLD 10
1549 * mono_method_alloc_generic_virtual_trampoline:
1550 * \param domain a domain
1551 * \param size size in bytes
1552 * Allocs \p size bytes to be used for the code of a generic virtual
1553 * trampoline. It's either allocated from the domain's code manager or
1554 * reused from a previously invalidated piece.
1555 * LOCKING: The domain lock must be held.
1558 mono_method_alloc_generic_virtual_trampoline (MonoDomain *domain, int size)
1560 MONO_REQ_GC_NEUTRAL_MODE;
1562 static gboolean inited = FALSE;
1563 static int generic_virtual_trampolines_size = 0;
1566 mono_counters_register ("Generic virtual trampoline bytes",
1567 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_trampolines_size);
1570 generic_virtual_trampolines_size += size;
1572 return mono_domain_code_reserve (domain, size);
1575 typedef struct _GenericVirtualCase {
1579 struct _GenericVirtualCase *next;
1580 } GenericVirtualCase;
1583 * get_generic_virtual_entries:
1585 * Return IMT entries for the generic virtual method instances and
1586 * variant interface methods for vtable slot
1589 static MonoImtBuilderEntry*
1590 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1592 MONO_REQ_GC_NEUTRAL_MODE;
1594 GenericVirtualCase *list;
1595 MonoImtBuilderEntry *entries;
1597 mono_domain_lock (domain);
1598 if (!domain->generic_virtual_cases)
1599 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1601 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1604 for (; list; list = list->next) {
1605 MonoImtBuilderEntry *entry;
1607 if (list->count < THUNK_THRESHOLD)
1610 entry = g_new0 (MonoImtBuilderEntry, 1);
1611 entry->key = list->method;
1612 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1613 entry->has_target_code = 1;
1615 entry->children = entries->children + 1;
1616 entry->next = entries;
1620 mono_domain_unlock (domain);
1622 /* FIXME: Leaking memory ? */
1627 * \param domain a domain
1628 * \param vtable_slot pointer to the vtable slot
1629 * \param method the inflated generic virtual method
1630 * \param code the method's code
1632 * Registers a call via unmanaged code to a generic virtual method
1633 * instantiation or variant interface method. If the number of calls reaches a threshold
1634 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1635 * virtual method trampoline.
1638 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1639 gpointer *vtable_slot,
1640 MonoMethod *method, gpointer code)
1642 MONO_REQ_GC_NEUTRAL_MODE;
1644 static gboolean inited = FALSE;
1645 static int num_added = 0;
1646 static int num_freed = 0;
1648 GenericVirtualCase *gvc, *list;
1649 MonoImtBuilderEntry *entries;
1653 mono_domain_lock (domain);
1654 if (!domain->generic_virtual_cases)
1655 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1658 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1659 mono_counters_register ("Freed IMT trampolines", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_freed);
1663 /* Check whether the case was already added */
1664 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1667 if (gvc->method == method)
1672 /* If not found, make a new one */
1674 gvc = (GenericVirtualCase *)mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1675 gvc->method = method;
1678 gvc->next = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1680 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1685 if (++gvc->count == THUNK_THRESHOLD) {
1686 gpointer *old_thunk = (void **)*vtable_slot;
1687 gpointer vtable_trampoline = NULL;
1688 gpointer imt_trampoline = NULL;
1690 if ((gpointer)vtable_slot < (gpointer)vtable) {
1691 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1692 int imt_slot = MONO_IMT_SIZE + displacement;
1694 /* Force the rebuild of the trampoline at the next call */
1695 imt_trampoline = callbacks.get_imt_trampoline (vtable, imt_slot);
1696 *vtable_slot = imt_trampoline;
1698 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline (vtable, (gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1700 entries = get_generic_virtual_entries (domain, vtable_slot);
1702 sorted = imt_sort_slot_entries (entries);
1704 *vtable_slot = imt_trampoline_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1708 MonoImtBuilderEntry *next = entries->next;
1713 for (i = 0; i < sorted->len; ++i)
1714 g_free (g_ptr_array_index (sorted, i));
1715 g_ptr_array_free (sorted, TRUE);
1717 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1722 mono_domain_unlock (domain);
1725 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error);
1728 * mono_class_vtable:
1729 * \param domain the application domain
1730 * \param class the class to initialize
1731 * VTables are domain specific because we create domain specific code, and
1732 * they contain the domain specific static class data.
1733 * On failure, NULL is returned, and \c class->exception_type is set.
1736 mono_class_vtable (MonoDomain *domain, MonoClass *klass)
1739 MonoVTable* vtable = mono_class_vtable_full (domain, klass, &error);
1740 mono_error_cleanup (&error);
1745 * mono_class_vtable_full:
1746 * \param domain the application domain
1747 * \param class the class to initialize
1748 * \param error set on failure.
1749 * VTables are domain specific because we create domain specific code, and
1750 * they contain the domain specific static class data.
1753 mono_class_vtable_full (MonoDomain *domain, MonoClass *klass, MonoError *error)
1755 MONO_REQ_GC_UNSAFE_MODE;
1757 MonoClassRuntimeInfo *runtime_info;
1763 if (mono_class_has_failure (klass)) {
1764 mono_error_set_for_class_failure (error, klass);
1768 /* this check can be inlined in jitted code, too */
1769 runtime_info = klass->runtime_info;
1770 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1771 return runtime_info->domain_vtables [domain->domain_id];
1772 return mono_class_create_runtime_vtable (domain, klass, error);
1776 * mono_class_try_get_vtable:
1777 * \param domain the application domain
1778 * \param class the class to initialize
1779 * This function tries to get the associated vtable from \p class if
1780 * it was already created.
1783 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *klass)
1785 MONO_REQ_GC_NEUTRAL_MODE;
1787 MonoClassRuntimeInfo *runtime_info;
1791 runtime_info = klass->runtime_info;
1792 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1793 return runtime_info->domain_vtables [domain->domain_id];
1798 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1800 MONO_REQ_GC_NEUTRAL_MODE;
1802 size_t alloc_offset;
1805 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1806 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1807 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1809 if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1810 g_assert ((imt_table_bytes & 7) == 4);
1817 return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1821 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error)
1823 MONO_REQ_GC_UNSAFE_MODE;
1826 MonoClassRuntimeInfo *runtime_info, *old_info;
1827 MonoClassField *field;
1829 int i, vtable_slots;
1830 size_t imt_table_bytes;
1832 guint32 vtable_size, class_size;
1834 gpointer *interface_offsets;
1838 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1839 mono_domain_lock (domain);
1840 runtime_info = klass->runtime_info;
1841 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1842 mono_domain_unlock (domain);
1843 mono_loader_unlock ();
1844 return runtime_info->domain_vtables [domain->domain_id];
1846 if (!klass->inited || mono_class_has_failure (klass)) {
1847 if (!mono_class_init (klass) || mono_class_has_failure (klass)) {
1848 mono_domain_unlock (domain);
1849 mono_loader_unlock ();
1850 mono_error_set_for_class_failure (error, klass);
1855 /* Array types require that their element type be valid*/
1856 if (klass->byval_arg.type == MONO_TYPE_ARRAY || klass->byval_arg.type == MONO_TYPE_SZARRAY) {
1857 MonoClass *element_class = klass->element_class;
1858 if (!element_class->inited)
1859 mono_class_init (element_class);
1861 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1862 if (!mono_class_has_failure (element_class) && !element_class->vtable_size)
1863 mono_class_setup_vtable (element_class);
1865 if (mono_class_has_failure (element_class)) {
1866 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1867 if (!mono_class_has_failure (klass))
1868 mono_class_set_type_load_failure (klass, "");
1869 mono_domain_unlock (domain);
1870 mono_loader_unlock ();
1871 mono_error_set_for_class_failure (error, klass);
1877 * For some classes, mono_class_init () already computed klass->vtable_size, and
1878 * that is all that is needed because of the vtable trampolines.
1880 if (!klass->vtable_size)
1881 mono_class_setup_vtable (klass);
1883 if (mono_class_is_ginst (klass) && !klass->vtable)
1884 mono_class_check_vtable_constraints (klass, NULL);
1886 /* Initialize klass->has_finalize */
1887 mono_class_has_finalizer (klass);
1889 if (mono_class_has_failure (klass)) {
1890 mono_domain_unlock (domain);
1891 mono_loader_unlock ();
1892 mono_error_set_for_class_failure (error, klass);
1896 vtable_slots = klass->vtable_size;
1897 /* we add an additional vtable slot to store the pointer to static field data only when needed */
1898 class_size = mono_class_data_size (klass);
1902 if (klass->interface_offsets_count) {
1903 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1904 UnlockedIncrement (&mono_stats.imt_number_of_tables);
1905 UnlockedAdd (&mono_stats.imt_tables_size, imt_table_bytes);
1907 imt_table_bytes = 0;
1910 vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
1912 UnlockedIncrement (&mono_stats.used_class_count);
1913 UnlockedAdd (&mono_stats.class_vtable_size, vtable_size);
1915 interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
1916 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1917 g_assert (!((gsize)vt & 7));
1920 vt->rank = klass->rank;
1921 vt->domain = domain;
1923 mono_class_compute_gc_descriptor (klass);
1926 * We can't use typed allocation in the non-root domains, since the
1927 * collector needs the GC descriptor stored in the vtable even after
1928 * the mempool containing the vtable is destroyed when the domain is
1929 * unloaded. An alternative might be to allocate vtables in the GC
1930 * heap, but this does not seem to work (it leads to crashes inside
1931 * libgc). If that approach is tried, two gc descriptors need to be
1932 * allocated for each class: one for the root domain, and one for all
1933 * other domains. The second descriptor should contain a bit for the
1934 * vtable field in MonoObject, since we can no longer assume the
1935 * vtable is reachable by other roots after the appdomain is unloaded.
1937 if (!mono_gc_is_moving () && domain != mono_get_root_domain () && !mono_dont_free_domains)
1938 vt->gc_descr = MONO_GC_DESCRIPTOR_NULL;
1940 vt->gc_descr = klass->gc_descr;
1942 gc_bits = mono_gc_get_vtable_bits (klass);
1943 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
1945 vt->gc_bits = gc_bits;
1948 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
1949 if (klass->has_static_refs) {
1950 MonoGCDescriptor statics_gc_descr;
1952 gsize default_bitmap [4] = {0};
1955 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1956 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], klass->name_space, klass->name, class_size);*/
1957 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1958 vt->vtable [klass->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr, MONO_ROOT_SOURCE_STATIC, "managed static variables");
1959 if (bitmap != default_bitmap)
1962 vt->vtable [klass->vtable_size] = mono_domain_alloc0 (domain, class_size);
1964 vt->has_static_fields = TRUE;
1965 UnlockedAdd (&mono_stats.class_static_data_size, class_size);
1969 while ((field = mono_class_get_fields (klass, &iter))) {
1970 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1972 if (mono_field_is_deleted (field))
1974 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1975 gint32 special_static = klass->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (klass, field);
1976 if (special_static != SPECIAL_STATIC_NONE) {
1977 guint32 size, offset;
1979 gsize default_bitmap [4] = {0};
1984 if (mono_type_is_reference (field->type)) {
1985 default_bitmap [0] = 1;
1987 bitmap = default_bitmap;
1988 } else if (mono_type_is_struct (field->type)) {
1989 fclass = mono_class_from_mono_type (field->type);
1990 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
1991 numbits = max_set + 1;
1993 default_bitmap [0] = 0;
1995 bitmap = default_bitmap;
1997 size = mono_type_size (field->type, &align);
1998 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
1999 if (!domain->special_static_fields)
2000 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2001 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2002 if (bitmap != default_bitmap)
2005 * This marks the field as special static to speed up the
2006 * checks in mono_field_static_get/set_value ().
2012 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2013 MonoClass *fklass = mono_class_from_mono_type (field->type);
2014 const char *data = mono_field_get_data (field);
2016 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2017 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2018 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2021 if (fklass->valuetype) {
2022 memcpy (t, data, mono_class_value_size (fklass, NULL));
2024 /* it's a pointer type: add check */
2025 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2032 vt->max_interface_id = klass->max_interface_id;
2033 vt->interface_bitmap = klass->interface_bitmap;
2035 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2036 // class->name, klass->interface_offsets_count);
2038 /* Initialize vtable */
2039 if (callbacks.get_vtable_trampoline) {
2040 // This also covers the AOT case
2041 for (i = 0; i < klass->vtable_size; ++i) {
2042 vt->vtable [i] = callbacks.get_vtable_trampoline (vt, i);
2045 mono_class_setup_vtable (klass);
2047 for (i = 0; i < klass->vtable_size; ++i) {
2050 cm = klass->vtable [i];
2052 vt->vtable [i] = callbacks.create_jit_trampoline (domain, cm, error);
2053 if (!is_ok (error)) {
2054 mono_domain_unlock (domain);
2055 mono_loader_unlock ();
2062 if (imt_table_bytes) {
2063 /* Now that the vtable is full, we can actually fill up the IMT */
2064 for (i = 0; i < MONO_IMT_SIZE; ++i)
2065 interface_offsets [i] = callbacks.get_imt_trampoline (vt, i);
2069 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2070 * re-acquire them and check if another thread has created the vtable in the meantime.
2072 /* Special case System.MonoType to avoid infinite recursion */
2073 if (klass != mono_defaults.runtimetype_class) {
2074 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2075 if (!is_ok (error)) {
2076 mono_domain_unlock (domain);
2077 mono_loader_unlock ();
2081 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2082 /* This is unregistered in
2083 unregister_vtable_reflection_type() in
2085 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2088 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (klass));
2090 /* class_vtable_array keeps an array of created vtables
2092 g_ptr_array_add (domain->class_vtable_array, vt);
2093 /* klass->runtime_info is protected by the loader lock, both when
2094 * it it enlarged and when it is stored info.
2098 * Store the vtable in klass->runtime_info.
2099 * klass->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2101 mono_memory_barrier ();
2103 old_info = klass->runtime_info;
2104 if (old_info && old_info->max_domain >= domain->domain_id) {
2105 /* someone already created a large enough runtime info */
2106 old_info->domain_vtables [domain->domain_id] = vt;
2108 int new_size = domain->domain_id;
2110 new_size = MAX (new_size, old_info->max_domain);
2112 /* make the new size a power of two */
2114 while (new_size > i)
2117 /* this is a bounded memory retention issue: may want to
2118 * handle it differently when we'll have a rcu-like system.
2120 runtime_info = (MonoClassRuntimeInfo *)mono_image_alloc0 (klass->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2121 runtime_info->max_domain = new_size - 1;
2122 /* copy the stuff from the older info */
2124 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2126 runtime_info->domain_vtables [domain->domain_id] = vt;
2128 mono_memory_barrier ();
2129 klass->runtime_info = runtime_info;
2132 if (klass == mono_defaults.runtimetype_class) {
2133 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2134 if (!is_ok (error)) {
2135 mono_domain_unlock (domain);
2136 mono_loader_unlock ();
2140 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2141 /* This is unregistered in
2142 unregister_vtable_reflection_type() in
2144 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2147 mono_domain_unlock (domain);
2148 mono_loader_unlock ();
2150 /* make sure the parent is initialized */
2151 /*FIXME shouldn't this fail the current type?*/
2153 mono_class_vtable_full (domain, klass->parent, error);
2158 #ifndef DISABLE_REMOTING
2160 * mono_remote_class_is_interface_proxy:
2161 * \param remote_class
2163 * Returns TRUE if the given remote class is a proxying an interface (as
2164 * opposed to a class deriving from MarshalByRefObject).
2167 mono_remote_class_is_interface_proxy (MonoRemoteClass *remote_class)
2169 /* This if condition is taking advantage of how mono_remote_class ()
2170 * works: if that code changes, this needs to change too. */
2171 return (remote_class->interface_count >= 1 &&
2172 remote_class->proxy_class == mono_defaults.marshalbyrefobject_class);
2176 * mono_class_proxy_vtable:
2177 * \param domain the application domain
2178 * \param remove_class the remote class
2179 * \param error set on error
2180 * Creates a vtable for transparent proxies. It is basically
2181 * a copy of the real vtable of the class wrapped in \p remote_class,
2182 * but all function pointers invoke the remoting functions, and
2183 * \c vtable->klass points to the transparent proxy class, and not to \p class.
2185 * On failure returns NULL and sets \p error
2188 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type, MonoError *error)
2190 MONO_REQ_GC_UNSAFE_MODE;
2192 MonoVTable *vt, *pvt;
2193 int i, j, vtsize, extra_interface_vtsize = 0;
2194 guint32 max_interface_id;
2196 GSList *extra_interfaces = NULL;
2197 MonoClass *klass = remote_class->proxy_class;
2198 gpointer *interface_offsets;
2199 uint8_t *bitmap = NULL;
2201 size_t imt_table_bytes;
2203 #ifdef COMPRESSED_INTERFACE_BITMAP
2209 vt = mono_class_vtable (domain, klass);
2210 g_assert (vt); /*FIXME property handle failure*/
2211 max_interface_id = vt->max_interface_id;
2213 /* Calculate vtable space for extra interfaces */
2214 for (j = 0; j < remote_class->interface_count; j++) {
2215 MonoClass* iclass = remote_class->interfaces[j];
2219 /*FIXME test for interfaces with variant generic arguments*/
2220 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, iclass->interface_id))
2221 continue; /* interface implemented by the class */
2222 if (g_slist_find (extra_interfaces, iclass))
2225 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2227 method_count = mono_class_num_methods (iclass);
2229 ifaces = mono_class_get_implemented_interfaces (iclass, error);
2233 for (i = 0; i < ifaces->len; ++i) {
2234 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2235 /*FIXME test for interfaces with variant generic arguments*/
2236 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, ic->interface_id))
2237 continue; /* interface implemented by the class */
2238 if (g_slist_find (extra_interfaces, ic))
2240 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2241 method_count += mono_class_num_methods (ic);
2243 g_ptr_array_free (ifaces, TRUE);
2247 extra_interface_vtsize += method_count * sizeof (gpointer);
2248 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2251 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2252 UnlockedIncrement (&mono_stats.imt_number_of_tables);
2253 UnlockedAdd (&mono_stats.imt_tables_size, imt_table_bytes);
2255 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer);
2257 UnlockedAdd (&mono_stats.class_vtable_size, vtsize + extra_interface_vtsize);
2259 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2260 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2261 g_assert (!((gsize)pvt & 7));
2263 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer));
2265 pvt->klass = mono_defaults.transparent_proxy_class;
2266 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2267 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2269 if (mono_remote_class_is_interface_proxy (remote_class)) {
2270 /* If it's a transparent proxy for an interface, set the
2271 * MonoVTable:type to the interface type, not the placeholder
2272 * MarshalByRefObject class. This is used when mini JITs calls
2273 * to Object.GetType ()
2275 MonoType *itf_proxy_type = &remote_class->interfaces[0]->byval_arg;
2276 pvt->type = mono_type_get_object_checked (domain, itf_proxy_type, error);
2281 /* initialize vtable */
2282 mono_class_setup_vtable (klass);
2283 for (i = 0; i < klass->vtable_size; ++i) {
2286 if ((cm = klass->vtable [i])) {
2287 pvt->vtable [i] = create_remoting_trampoline (domain, cm, target_type, error);
2291 pvt->vtable [i] = NULL;
2294 if (mono_class_is_abstract (klass)) {
2295 /* create trampolines for abstract methods */
2296 for (k = klass; k; k = k->parent) {
2298 gpointer iter = NULL;
2299 while ((m = mono_class_get_methods (k, &iter)))
2300 if (!pvt->vtable [m->slot]) {
2301 pvt->vtable [m->slot] = create_remoting_trampoline (domain, m, target_type, error);
2308 pvt->max_interface_id = max_interface_id;
2309 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2310 #ifdef COMPRESSED_INTERFACE_BITMAP
2311 bitmap = (uint8_t *)g_malloc0 (bsize);
2313 bitmap = (uint8_t *)mono_domain_alloc0 (domain, bsize);
2316 for (i = 0; i < klass->interface_offsets_count; ++i) {
2317 int interface_id = klass->interfaces_packed [i]->interface_id;
2318 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2321 if (extra_interfaces) {
2322 int slot = klass->vtable_size;
2328 /* Create trampolines for the methods of the interfaces */
2329 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2330 interf = (MonoClass *)list_item->data;
2332 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2336 while ((cm = mono_class_get_methods (interf, &iter))) {
2337 pvt->vtable [slot + j++] = create_remoting_trampoline (domain, cm, target_type, error);
2342 slot += mono_class_num_methods (interf);
2346 /* Now that the vtable is full, we can actually fill up the IMT */
2347 build_imt (klass, pvt, domain, interface_offsets, extra_interfaces);
2348 if (extra_interfaces) {
2349 g_slist_free (extra_interfaces);
2352 #ifdef COMPRESSED_INTERFACE_BITMAP
2353 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2354 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2355 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2358 pvt->interface_bitmap = bitmap;
2362 if (extra_interfaces)
2363 g_slist_free (extra_interfaces);
2364 #ifdef COMPRESSED_INTERFACE_BITMAP
2370 #endif /* DISABLE_REMOTING */
2373 * mono_class_field_is_special_static:
2374 * \returns whether \p field is a thread/context static field.
2377 mono_class_field_is_special_static (MonoClassField *field)
2379 MONO_REQ_GC_NEUTRAL_MODE
2381 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2383 if (mono_field_is_deleted (field))
2385 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2386 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2393 * mono_class_field_get_special_static_type:
2394 * \param field The \c MonoClassField describing the field.
2395 * \returns \c SPECIAL_STATIC_THREAD if the field is thread static, \c SPECIAL_STATIC_CONTEXT if it is context static,
2396 * \c SPECIAL_STATIC_NONE otherwise.
2399 mono_class_field_get_special_static_type (MonoClassField *field)
2401 MONO_REQ_GC_NEUTRAL_MODE
2403 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2404 return SPECIAL_STATIC_NONE;
2405 if (mono_field_is_deleted (field))
2406 return SPECIAL_STATIC_NONE;
2407 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2408 return field_is_special_static (field->parent, field);
2409 return SPECIAL_STATIC_NONE;
2413 * mono_class_has_special_static_fields:
2414 * \returns whether \p klass has any thread/context static fields.
2417 mono_class_has_special_static_fields (MonoClass *klass)
2419 MONO_REQ_GC_NEUTRAL_MODE
2421 MonoClassField *field;
2425 while ((field = mono_class_get_fields (klass, &iter))) {
2426 g_assert (field->parent == klass);
2427 if (mono_class_field_is_special_static (field))
2434 #ifndef DISABLE_REMOTING
2436 * create_remote_class_key:
2437 * Creates an array of pointers that can be used as a hash key for a remote class.
2438 * The first element of the array is the number of pointers.
2441 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2443 MONO_REQ_GC_NEUTRAL_MODE;
2448 if (remote_class == NULL) {
2449 if (mono_class_is_interface (extra_class)) {
2450 key = (void **)g_malloc (sizeof(gpointer) * 3);
2451 key [0] = GINT_TO_POINTER (2);
2452 key [1] = mono_defaults.marshalbyrefobject_class;
2453 key [2] = extra_class;
2455 key = (void **)g_malloc (sizeof(gpointer) * 2);
2456 key [0] = GINT_TO_POINTER (1);
2457 key [1] = extra_class;
2460 if (extra_class != NULL && mono_class_is_interface (extra_class)) {
2461 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2462 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2463 key [1] = remote_class->proxy_class;
2465 // Keep the list of interfaces sorted
2466 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2467 if (extra_class && remote_class->interfaces [i] > extra_class) {
2468 key [j++] = extra_class;
2471 key [j] = remote_class->interfaces [i];
2474 key [j] = extra_class;
2476 // Replace the old class. The interface list is the same
2477 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2478 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2479 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2480 for (i = 0; i < remote_class->interface_count; i++)
2481 key [2 + i] = remote_class->interfaces [i];
2489 * copy_remote_class_key:
2491 * Make a copy of KEY in the domain and return the copy.
2494 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2496 MONO_REQ_GC_NEUTRAL_MODE
2498 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2499 gpointer *mp_key = (gpointer *)mono_domain_alloc (domain, key_size);
2501 memcpy (mp_key, key, key_size);
2507 * mono_remote_class:
2508 * \param domain the application domain
2509 * \param class_name name of the remote class
2510 * \param error set on error
2511 * Creates and initializes a \c MonoRemoteClass object for a remote type.
2512 * On failure returns NULL and sets \p error
2515 mono_remote_class (MonoDomain *domain, MonoStringHandle class_name, MonoClass *proxy_class, MonoError *error)
2517 MONO_REQ_GC_UNSAFE_MODE;
2519 MonoRemoteClass *rc;
2520 gpointer* key, *mp_key;
2525 key = create_remote_class_key (NULL, proxy_class);
2527 mono_domain_lock (domain);
2528 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2532 mono_domain_unlock (domain);
2536 name = mono_string_to_utf8_mp (domain->mp, MONO_HANDLE_RAW (class_name), error);
2537 if (!is_ok (error)) {
2539 mono_domain_unlock (domain);
2543 mp_key = copy_remote_class_key (domain, key);
2547 if (mono_class_is_interface (proxy_class)) {
2548 /* If we need to proxy an interface, we use this stylized
2549 * representation (interface_count >= 1, proxy_class is
2550 * MarshalByRefObject). The code in
2551 * mono_remote_class_is_interface_proxy () depends on being
2552 * able to detect that we're doing this, so if this
2553 * representation changes, change GetType, too. */
2554 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2555 rc->interface_count = 1;
2556 rc->interfaces [0] = proxy_class;
2557 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2559 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2560 rc->interface_count = 0;
2561 rc->proxy_class = proxy_class;
2564 rc->default_vtable = NULL;
2565 rc->xdomain_vtable = NULL;
2566 rc->proxy_class_name = name;
2567 #ifndef DISABLE_PERFCOUNTERS
2568 InterlockedAdd (&mono_perfcounters->loader_bytes, mono_string_length (MONO_HANDLE_RAW (class_name)) + 1);
2571 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2573 mono_domain_unlock (domain);
2578 * clone_remote_class:
2579 * Creates a copy of the remote_class, adding the provided class or interface
2581 static MonoRemoteClass*
2582 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2584 MONO_REQ_GC_NEUTRAL_MODE;
2586 MonoRemoteClass *rc;
2587 gpointer* key, *mp_key;
2589 key = create_remote_class_key (remote_class, extra_class);
2590 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2596 mp_key = copy_remote_class_key (domain, key);
2600 if (mono_class_is_interface (extra_class)) {
2602 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2603 rc->proxy_class = remote_class->proxy_class;
2604 rc->interface_count = remote_class->interface_count + 1;
2606 // Keep the list of interfaces sorted, since the hash key of
2607 // the remote class depends on this
2608 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2609 if (remote_class->interfaces [i] > extra_class && i == j)
2610 rc->interfaces [j++] = extra_class;
2611 rc->interfaces [j] = remote_class->interfaces [i];
2614 rc->interfaces [j] = extra_class;
2616 // Replace the old class. The interface array is the same
2617 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2618 rc->proxy_class = extra_class;
2619 rc->interface_count = remote_class->interface_count;
2620 if (rc->interface_count > 0)
2621 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2624 rc->default_vtable = NULL;
2625 rc->xdomain_vtable = NULL;
2626 rc->proxy_class_name = remote_class->proxy_class_name;
2628 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2634 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxyHandle rp, MonoError *error)
2636 MONO_REQ_GC_UNSAFE_MODE;
2640 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2641 mono_domain_lock (domain);
2642 gint32 target_domain_id = MONO_HANDLE_GETVAL (rp, target_domain_id);
2643 if (target_domain_id != -1) {
2644 if (remote_class->xdomain_vtable == NULL)
2645 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN, error);
2646 mono_domain_unlock (domain);
2647 mono_loader_unlock ();
2648 return_val_if_nok (error, NULL);
2649 return remote_class->xdomain_vtable;
2651 if (remote_class->default_vtable == NULL) {
2652 MonoReflectionTypeHandle reftype = MONO_HANDLE_NEW (MonoReflectionType, NULL);
2653 MONO_HANDLE_GET (reftype, rp, class_to_proxy);
2655 MonoType *type = MONO_HANDLE_GETVAL (reftype, type);
2656 MonoClass *klass = mono_class_from_mono_type (type);
2658 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)))
2659 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP, error);
2662 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN, error);
2663 /* N.B. both branches of the if modify error */
2664 if (!is_ok (error)) {
2665 mono_domain_unlock (domain);
2666 mono_loader_unlock ();
2671 mono_domain_unlock (domain);
2672 mono_loader_unlock ();
2673 return remote_class->default_vtable;
2677 * mono_upgrade_remote_class:
2678 * \param domain the application domain
2679 * \param tproxy the proxy whose remote class has to be upgraded.
2680 * \param klass class to which the remote class can be casted.
2681 * \param error set on error
2682 * Updates the vtable of the remote class by adding the necessary method slots
2683 * and interface offsets so it can be safely casted to klass. klass can be a
2684 * class or an interface. On success returns TRUE, on failure returns FALSE and sets \p error.
2687 mono_upgrade_remote_class (MonoDomain *domain, MonoObjectHandle proxy_object, MonoClass *klass, MonoError *error)
2689 MONO_REQ_GC_UNSAFE_MODE;
2693 MonoTransparentProxyHandle tproxy = MONO_HANDLE_CAST (MonoTransparentProxy, proxy_object);
2694 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (tproxy, remote_class);
2696 gboolean redo_vtable;
2697 if (mono_class_is_interface (klass)) {
2700 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2701 if (remote_class->interfaces [i] == klass)
2702 redo_vtable = FALSE;
2705 redo_vtable = (remote_class->proxy_class != klass);
2708 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2709 mono_domain_lock (domain);
2711 MonoRemoteClass *fresh_remote_class = clone_remote_class (domain, remote_class, klass);
2712 MONO_HANDLE_SETVAL (tproxy, remote_class, MonoRemoteClass*, fresh_remote_class);
2713 MonoRealProxyHandle real_proxy = MONO_HANDLE_NEW (MonoRealProxy, NULL);
2714 MONO_HANDLE_GET (real_proxy, tproxy, rp);
2715 MONO_HANDLE_SETVAL (proxy_object, vtable, MonoVTable*, mono_remote_class_vtable (domain, fresh_remote_class, real_proxy, error));
2721 mono_domain_unlock (domain);
2722 mono_loader_unlock ();
2723 return is_ok (error);
2725 #endif /* DISABLE_REMOTING */
2729 * mono_object_get_virtual_method:
2730 * \param obj object to operate on.
2731 * \param method method
2732 * Retrieves the \c MonoMethod that would be called on \p obj if \p obj is passed as
2733 * the instance of a callvirt of \p method.
2736 mono_object_get_virtual_method (MonoObject *obj_raw, MonoMethod *method)
2738 MONO_REQ_GC_UNSAFE_MODE;
2739 HANDLE_FUNCTION_ENTER ();
2741 MONO_HANDLE_DCL (MonoObject, obj);
2742 MonoMethod *result = mono_object_handle_get_virtual_method (obj, method, &error);
2743 mono_error_assert_ok (&error);
2744 HANDLE_FUNCTION_RETURN_VAL (result);
2748 * mono_object_handle_get_virtual_method:
2749 * \param obj object to operate on.
2750 * \param method method
2751 * Retrieves the \c MonoMethod that would be called on \p obj if \p obj is passed as
2752 * the instance of a callvirt of \p method.
2755 mono_object_handle_get_virtual_method (MonoObjectHandle obj, MonoMethod *method, MonoError *error)
2759 gboolean is_proxy = FALSE;
2760 MonoClass *klass = mono_handle_class (obj);
2761 if (mono_class_is_transparent_proxy (klass)) {
2762 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), remote_class);
2763 klass = remote_class->proxy_class;
2766 return class_get_virtual_method (klass, method, is_proxy, error);
2770 class_get_virtual_method (MonoClass *klass, MonoMethod *method, gboolean is_proxy, MonoError *error)
2775 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2778 mono_class_setup_vtable (klass);
2779 MonoMethod **vtable = klass->vtable;
2781 if (method->slot == -1) {
2782 /* method->slot might not be set for instances of generic methods */
2783 if (method->is_inflated) {
2784 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2785 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2788 g_assert_not_reached ();
2792 MonoMethod *res = NULL;
2793 /* check method->slot is a valid index: perform isinstance? */
2794 if (method->slot != -1) {
2795 if (mono_class_is_interface (method->klass)) {
2797 gboolean variance_used = FALSE;
2798 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2799 g_assert (iface_offset > 0);
2800 res = vtable [iface_offset + method->slot];
2803 res = vtable [method->slot];
2807 #ifndef DISABLE_REMOTING
2809 /* It may be an interface, abstract class method or generic method */
2810 if (!res || mono_method_signature (res)->generic_param_count)
2813 /* generic methods demand invoke_with_check */
2814 if (mono_method_signature (res)->generic_param_count)
2815 res = mono_marshal_get_remoting_invoke_with_check (res);
2818 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2819 res = mono_cominterop_get_invoke (res);
2822 res = mono_marshal_get_remoting_invoke (res);
2827 if (method->is_inflated) {
2828 /* Have to inflate the result */
2829 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, error);
2837 do_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2839 MONO_REQ_GC_UNSAFE_MODE;
2841 MonoObject *result = NULL;
2843 g_assert (callbacks.runtime_invoke);
2847 MONO_PROFILER_RAISE (method_begin_invoke, (method));
2849 result = callbacks.runtime_invoke (method, obj, params, exc, error);
2851 MONO_PROFILER_RAISE (method_end_invoke, (method));
2853 if (!mono_error_ok (error))
2860 * mono_runtime_invoke:
2861 * \param method method to invoke
2862 * \param obj object instance
2863 * \param params arguments to the method
2864 * \param exc exception information.
2865 * Invokes the method represented by \p method on the object \p obj.
2866 * \p obj is the \c this pointer, it should be NULL for static
2867 * methods, a \c MonoObject* for object instances and a pointer to
2868 * the value type for value types.
2870 * The params array contains the arguments to the method with the
2871 * same convention: \c MonoObject* pointers for object instances and
2872 * pointers to the value type otherwise.
2874 * From unmanaged code you'll usually use the
2875 * \c mono_runtime_invoke variant.
2877 * Note that this function doesn't handle virtual methods for
2878 * you, it will exec the exact method you pass: we still need to
2879 * expose a function to lookup the derived class implementation
2880 * of a virtual method (there are examples of this in the code,
2883 * You can pass NULL as the \p exc argument if you don't want to
2884 * catch exceptions, otherwise, \c *exc will be set to the exception
2885 * thrown, if any. if an exception is thrown, you can't use the
2886 * \c MonoObject* result from the function.
2888 * If the method returns a value type, it is boxed in an object
2892 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2897 res = mono_runtime_try_invoke (method, obj, params, exc, &error);
2898 if (*exc == NULL && !mono_error_ok(&error)) {
2899 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
2901 mono_error_cleanup (&error);
2903 res = mono_runtime_invoke_checked (method, obj, params, &error);
2904 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
2910 * mono_runtime_try_invoke:
2911 * \param method method to invoke
2912 * \param obj object instance
2913 * \param params arguments to the method
2914 * \param exc exception information.
2915 * \param error set on error
2916 * Invokes the method represented by \p method on the object \p obj.
2918 * \p obj is the \c this pointer, it should be NULL for static
2919 * methods, a \c MonoObject* for object instances and a pointer to
2920 * the value type for value types.
2922 * The params array contains the arguments to the method with the
2923 * same convention: \c MonoObject* pointers for object instances and
2924 * pointers to the value type otherwise.
2926 * From unmanaged code you'll usually use the
2927 * mono_runtime_invoke() variant.
2929 * Note that this function doesn't handle virtual methods for
2930 * you, it will exec the exact method you pass: we still need to
2931 * expose a function to lookup the derived class implementation
2932 * of a virtual method (there are examples of this in the code,
2935 * For this function, you must not pass NULL as the \p exc argument if
2936 * you don't want to catch exceptions, use
2937 * mono_runtime_invoke_checked(). If an exception is thrown, you
2938 * can't use the \c MonoObject* result from the function.
2940 * If this method cannot be invoked, \p error will be set and \p exc and
2941 * the return value must not be used.
2943 * If the method returns a value type, it is boxed in an object
2947 mono_runtime_try_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError* error)
2949 MONO_REQ_GC_UNSAFE_MODE;
2951 g_assert (exc != NULL);
2953 if (mono_runtime_get_no_exec ())
2954 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2956 return do_runtime_invoke (method, obj, params, exc, error);
2960 * mono_runtime_invoke_checked:
2961 * \param method method to invoke
2962 * \param obj object instance
2963 * \param params arguments to the method
2964 * \param error set on error
2965 * Invokes the method represented by \p method on the object \p obj.
2967 * \p obj is the \c this pointer, it should be NULL for static
2968 * methods, a \c MonoObject* for object instances and a pointer to
2969 * the value type for value types.
2971 * The \p params array contains the arguments to the method with the
2972 * same convention: \c MonoObject* pointers for object instances and
2973 * pointers to the value type otherwise.
2975 * From unmanaged code you'll usually use the
2976 * mono_runtime_invoke() variant.
2978 * Note that this function doesn't handle virtual methods for
2979 * you, it will exec the exact method you pass: we still need to
2980 * expose a function to lookup the derived class implementation
2981 * of a virtual method (there are examples of this in the code,
2984 * If an exception is thrown, you can't use the \c MonoObject* result
2985 * from the function.
2987 * If this method cannot be invoked, \p error will be set. If the
2988 * method throws an exception (and we're in coop mode) the exception
2989 * will be set in \p error.
2991 * If the method returns a value type, it is boxed in an object
2995 mono_runtime_invoke_checked (MonoMethod *method, void *obj, void **params, MonoError* error)
2997 MONO_REQ_GC_UNSAFE_MODE;
2999 if (mono_runtime_get_no_exec ())
3000 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
3002 return do_runtime_invoke (method, obj, params, NULL, error);
3006 * mono_method_get_unmanaged_thunk:
3007 * \param method method to generate a thunk for.
3009 * Returns an \c unmanaged->managed thunk that can be used to call
3010 * a managed method directly from C.
3012 * The thunk's C signature closely matches the managed signature:
3014 * C#: <code>public bool Equals (object obj);</code>
3016 * C: <code>typedef MonoBoolean (*Equals)(MonoObject*, MonoObject*, MonoException**);</code>
3018 * The 1st (<code>this</code>) parameter must not be used with static methods:
3020 * C#: <code>public static bool ReferenceEquals (object a, object b);</code>
3022 * C: <code>typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*, MonoException**);</code>
3024 * The last argument must be a non-null \c MonoException* pointer.
3025 * It has "out" semantics. After invoking the thunk, \c *ex will be NULL if no
3026 * exception has been thrown in managed code. Otherwise it will point
3027 * to the \c MonoException* caught by the thunk. In this case, the result of
3028 * the thunk is undefined:
3031 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
3033 * MonoException *ex = NULL;
3035 * Equals func = mono_method_get_unmanaged_thunk (method);
3037 * MonoBoolean res = func (thisObj, objToCompare, &ex);
3041 * // handle exception
3046 * The calling convention of the thunk matches the platform's default
3047 * convention. This means that under Windows, C declarations must
3048 * contain the \c __stdcall attribute:
3050 * C: <code>typedef MonoBoolean (__stdcall *Equals)(MonoObject*, MonoObject*, MonoException**);</code>
3054 * Value type arguments and return values are treated as they were objects:
3056 * C#: <code>public static Rectangle Intersect (Rectangle a, Rectangle b);</code>
3057 * C: <code>typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);</code>
3059 * Arguments must be properly boxed upon trunk's invocation, while return
3060 * values must be unboxed.
3063 mono_method_get_unmanaged_thunk (MonoMethod *method)
3065 MONO_REQ_GC_NEUTRAL_MODE;
3066 MONO_REQ_API_ENTRYPOINT;
3071 g_assert (!mono_threads_is_coop_enabled ());
3073 MONO_ENTER_GC_UNSAFE;
3074 method = mono_marshal_get_thunk_invoke_wrapper (method);
3075 res = mono_compile_method_checked (method, &error);
3076 mono_error_cleanup (&error);
3077 MONO_EXIT_GC_UNSAFE;
3083 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
3085 MONO_REQ_GC_UNSAFE_MODE;
3089 /* object fields cannot be byref, so we don't need a
3091 gpointer *p = (gpointer*)dest;
3098 case MONO_TYPE_BOOLEAN:
3100 case MONO_TYPE_U1: {
3101 guint8 *p = (guint8*)dest;
3102 *p = value ? *(guint8*)value : 0;
3107 case MONO_TYPE_CHAR: {
3108 guint16 *p = (guint16*)dest;
3109 *p = value ? *(guint16*)value : 0;
3112 #if SIZEOF_VOID_P == 4
3117 case MONO_TYPE_U4: {
3118 gint32 *p = (gint32*)dest;
3119 *p = value ? *(gint32*)value : 0;
3122 #if SIZEOF_VOID_P == 8
3127 case MONO_TYPE_U8: {
3128 gint64 *p = (gint64*)dest;
3129 *p = value ? *(gint64*)value : 0;
3132 case MONO_TYPE_R4: {
3133 float *p = (float*)dest;
3134 *p = value ? *(float*)value : 0;
3137 case MONO_TYPE_R8: {
3138 double *p = (double*)dest;
3139 *p = value ? *(double*)value : 0;
3142 case MONO_TYPE_STRING:
3143 case MONO_TYPE_SZARRAY:
3144 case MONO_TYPE_CLASS:
3145 case MONO_TYPE_OBJECT:
3146 case MONO_TYPE_ARRAY:
3147 mono_gc_wbarrier_generic_store (dest, deref_pointer ? *(MonoObject **)value : (MonoObject *)value);
3149 case MONO_TYPE_FNPTR:
3150 case MONO_TYPE_PTR: {
3151 gpointer *p = (gpointer*)dest;
3152 *p = deref_pointer? *(gpointer*)value: value;
3155 case MONO_TYPE_VALUETYPE:
3156 /* note that 't' and 'type->type' can be different */
3157 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3158 t = mono_class_enum_basetype (type->data.klass)->type;
3161 MonoClass *klass = mono_class_from_mono_type (type);
3162 int size = mono_class_value_size (klass, NULL);
3164 mono_gc_bzero_atomic (dest, size);
3166 mono_gc_wbarrier_value_copy (dest, value, 1, klass);
3169 case MONO_TYPE_GENERICINST:
3170 t = type->data.generic_class->container_class->byval_arg.type;
3173 g_error ("got type %x", type->type);
3178 * mono_field_set_value:
3179 * \param obj Instance object
3180 * \param field \c MonoClassField describing the field to set
3181 * \param value The value to be set
3183 * Sets the value of the field described by \p field in the object instance \p obj
3184 * to the value passed in \p value. This method should only be used for instance
3185 * fields. For static fields, use \c mono_field_static_set_value.
3187 * The value must be in the native format of the field type.
3190 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3192 MONO_REQ_GC_UNSAFE_MODE;
3196 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3198 dest = (char*)obj + field->offset;
3199 mono_copy_value (field->type, dest, value, FALSE);
3203 * mono_field_static_set_value:
3204 * \param field \c MonoClassField describing the field to set
3205 * \param value The value to be set
3206 * Sets the value of the static field described by \p field
3207 * to the value passed in \p value.
3208 * The value must be in the native format of the field type.
3211 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3213 MONO_REQ_GC_UNSAFE_MODE;
3217 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3218 /* you cant set a constant! */
3219 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3221 if (field->offset == -1) {
3222 /* Special static */
3225 mono_domain_lock (vt->domain);
3226 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3227 mono_domain_unlock (vt->domain);
3228 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3230 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3232 mono_copy_value (field->type, dest, value, FALSE);
3236 * mono_vtable_get_static_field_data:
3238 * Internal use function: return a pointer to the memory holding the static fields
3239 * for a class or NULL if there are no static fields.
3240 * This is exported only for use by the debugger.
3243 mono_vtable_get_static_field_data (MonoVTable *vt)
3245 MONO_REQ_GC_NEUTRAL_MODE
3247 if (!vt->has_static_fields)
3249 return vt->vtable [vt->klass->vtable_size];
3253 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3255 MONO_REQ_GC_UNSAFE_MODE;
3259 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3260 if (field->offset == -1) {
3261 /* Special static */
3264 mono_domain_lock (vt->domain);
3265 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3266 mono_domain_unlock (vt->domain);
3267 src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3269 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3272 src = (guint8*)obj + field->offset;
3279 * mono_field_get_value:
3280 * \param obj Object instance
3281 * \param field \c MonoClassField describing the field to fetch information from
3282 * \param value pointer to the location where the value will be stored
3283 * Use this routine to get the value of the field \p field in the object
3286 * The pointer provided by value must be of the field type, for reference
3287 * types this is a \c MonoObject*, for value types its the actual pointer to
3295 * mono_field_get_value (obj, int_field, &i);
3299 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3301 MONO_REQ_GC_UNSAFE_MODE;
3307 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3309 src = (char*)obj + field->offset;
3310 mono_copy_value (field->type, value, src, TRUE);
3314 * mono_field_get_value_object:
3315 * \param domain domain where the object will be created (if boxing)
3316 * \param field \c MonoClassField describing the field to fetch information from
3317 * \param obj The object instance for the field.
3318 * \returns a new \c MonoObject with the value from the given field. If the
3319 * field represents a value type, the value is boxed.
3322 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3325 MonoObject* result = mono_field_get_value_object_checked (domain, field, obj, &error);
3326 mono_error_assert_ok (&error);
3331 * mono_field_get_value_object_checked:
3332 * \param domain domain where the object will be created (if boxing)
3333 * \param field \c MonoClassField describing the field to fetch information from
3334 * \param obj The object instance for the field.
3335 * \param error Set on error.
3336 * \returns a new \c MonoObject with the value from the given field. If the
3337 * field represents a value type, the value is boxed. On error returns NULL and sets \p error.
3340 mono_field_get_value_object_checked (MonoDomain *domain, MonoClassField *field, MonoObject *obj, MonoError *error)
3342 MONO_REQ_GC_UNSAFE_MODE;
3348 MonoVTable *vtable = NULL;
3350 gboolean is_static = FALSE;
3351 gboolean is_ref = FALSE;
3352 gboolean is_literal = FALSE;
3353 gboolean is_ptr = FALSE;
3354 MonoType *type = mono_field_get_type_checked (field, error);
3356 return_val_if_nok (error, NULL);
3358 switch (type->type) {
3359 case MONO_TYPE_STRING:
3360 case MONO_TYPE_OBJECT:
3361 case MONO_TYPE_CLASS:
3362 case MONO_TYPE_ARRAY:
3363 case MONO_TYPE_SZARRAY:
3368 case MONO_TYPE_BOOLEAN:
3371 case MONO_TYPE_CHAR:
3380 case MONO_TYPE_VALUETYPE:
3381 is_ref = type->byref;
3383 case MONO_TYPE_GENERICINST:
3384 is_ref = !mono_type_generic_inst_is_valuetype (type);
3390 g_error ("type 0x%x not handled in "
3391 "mono_field_get_value_object", type->type);
3395 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3398 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3402 vtable = mono_class_vtable_full (domain, field->parent, error);
3403 return_val_if_nok (error, NULL);
3405 if (!vtable->initialized) {
3406 mono_runtime_class_init_full (vtable, error);
3407 return_val_if_nok (error, NULL);
3416 get_default_field_value (domain, field, &o, error);
3417 return_val_if_nok (error, NULL);
3418 } else if (is_static) {
3419 mono_field_static_get_value_checked (vtable, field, &o, error);
3420 return_val_if_nok (error, NULL);
3422 mono_field_get_value (obj, field, &o);
3428 static MonoMethod *m;
3434 MonoClass *ptr_klass = mono_class_get_pointer_class ();
3435 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3441 get_default_field_value (domain, field, v, error);
3442 return_val_if_nok (error, NULL);
3443 } else if (is_static) {
3444 mono_field_static_get_value_checked (vtable, field, v, error);
3445 return_val_if_nok (error, NULL);
3447 mono_field_get_value (obj, field, v);
3450 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3451 args [0] = ptr ? *ptr : NULL;
3452 args [1] = mono_type_get_object_checked (mono_domain_get (), type, error);
3453 return_val_if_nok (error, NULL);
3455 o = mono_runtime_invoke_checked (m, NULL, args, error);
3456 return_val_if_nok (error, NULL);
3461 /* boxed value type */
3462 klass = mono_class_from_mono_type (type);
3464 if (mono_class_is_nullable (klass))
3465 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass, error);
3467 o = mono_object_new_checked (domain, klass, error);
3468 return_val_if_nok (error, NULL);
3469 v = ((gchar *) o) + sizeof (MonoObject);
3472 get_default_field_value (domain, field, v, error);
3473 return_val_if_nok (error, NULL);
3474 } else if (is_static) {
3475 mono_field_static_get_value_checked (vtable, field, v, error);
3476 return_val_if_nok (error, NULL);
3478 mono_field_get_value (obj, field, v);
3485 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value, MonoError *error)
3487 MONO_REQ_GC_UNSAFE_MODE;
3491 const char *p = blob;
3492 mono_metadata_decode_blob_size (p, &p);
3495 case MONO_TYPE_BOOLEAN:
3498 *(guint8 *) value = *p;
3500 case MONO_TYPE_CHAR:
3503 *(guint16*) value = read16 (p);
3507 *(guint32*) value = read32 (p);
3511 *(guint64*) value = read64 (p);
3514 readr4 (p, (float*) value);
3517 readr8 (p, (double*) value);
3519 case MONO_TYPE_STRING:
3520 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob, error);
3522 case MONO_TYPE_CLASS:
3523 *(gpointer*) value = NULL;
3527 g_warning ("type 0x%02x should not be in constant table", type);
3533 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error)
3535 MONO_REQ_GC_NEUTRAL_MODE;
3537 MonoTypeEnum def_type;
3542 data = mono_class_get_field_default_value (field, &def_type);
3543 mono_get_constant_value_from_blob (domain, def_type, data, value, error);
3547 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3549 MONO_REQ_GC_UNSAFE_MODE;
3555 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3557 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3558 get_default_field_value (vt->domain, field, value, error);
3562 if (field->offset == -1) {
3563 /* Special static */
3564 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3565 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3567 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3569 mono_copy_value (field->type, value, src, TRUE);
3573 * mono_field_static_get_value:
3574 * \param vt vtable to the object
3575 * \param field \c MonoClassField describing the field to fetch information from
3576 * \param value where the value is returned
3577 * Use this routine to get the value of the static field \p field value.
3579 * The pointer provided by value must be of the field type, for reference
3580 * types this is a \c MonoObject*, for value types its the actual pointer to
3588 * mono_field_static_get_value (vt, int_field, &i);
3592 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3594 MONO_REQ_GC_NEUTRAL_MODE;
3597 mono_field_static_get_value_checked (vt, field, value, &error);
3598 mono_error_cleanup (&error);
3602 * mono_field_static_get_value_checked:
3603 * \param vt vtable to the object
3604 * \param field \c MonoClassField describing the field to fetch information from
3605 * \param value where the value is returned
3606 * \param error set on error
3607 * Use this routine to get the value of the static field \p field value.
3609 * The pointer provided by value must be of the field type, for reference
3610 * types this is a \c MonoObject*, for value types its the actual pointer to
3615 * mono_field_static_get_value_checked (vt, int_field, &i, error);
3616 * if (!is_ok (error)) { ... }
3618 * On failure sets \p error.
3621 mono_field_static_get_value_checked (MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3623 MONO_REQ_GC_NEUTRAL_MODE;
3625 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value, error);
3629 * mono_property_set_value:
3630 * \param prop MonoProperty to set
3631 * \param obj instance object on which to act
3632 * \param params parameters to pass to the propery
3633 * \param exc optional exception
3634 * Invokes the property's set method with the given arguments on the
3635 * object instance obj (or NULL for static properties).
3637 * You can pass NULL as the exc argument if you don't want to
3638 * catch exceptions, otherwise, \c *exc will be set to the exception
3639 * thrown, if any. if an exception is thrown, you can't use the
3640 * \c MonoObject* result from the function.
3643 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3645 MONO_REQ_GC_UNSAFE_MODE;
3648 do_runtime_invoke (prop->set, obj, params, exc, &error);
3649 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3650 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3652 mono_error_cleanup (&error);
3657 * mono_property_set_value_checked:
3658 * \param prop \c MonoProperty to set
3659 * \param obj instance object on which to act
3660 * \param params parameters to pass to the propery
3661 * \param error set on error
3662 * Invokes the property's set method with the given arguments on the
3663 * object instance \p obj (or NULL for static properties).
3664 * \returns TRUE on success. On failure returns FALSE and sets \p error.
3665 * If an exception is thrown, it will be caught and returned via \p error.
3668 mono_property_set_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3670 MONO_REQ_GC_UNSAFE_MODE;
3675 do_runtime_invoke (prop->set, obj, params, &exc, error);
3676 if (exc != NULL && is_ok (error))
3677 mono_error_set_exception_instance (error, (MonoException*)exc);
3678 return is_ok (error);
3682 * mono_property_get_value:
3683 * \param prop \c MonoProperty to fetch
3684 * \param obj instance object on which to act
3685 * \param params parameters to pass to the propery
3686 * \param exc optional exception
3687 * Invokes the property's \c get method with the given arguments on the
3688 * object instance \p obj (or NULL for static properties).
3690 * You can pass NULL as the \p exc argument if you don't want to
3691 * catch exceptions, otherwise, \c *exc will be set to the exception
3692 * thrown, if any. if an exception is thrown, you can't use the
3693 * \c MonoObject* result from the function.
3695 * \returns the value from invoking the \c get method on the property.
3698 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3700 MONO_REQ_GC_UNSAFE_MODE;
3703 MonoObject *val = do_runtime_invoke (prop->get, obj, params, exc, &error);
3704 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3705 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3707 mono_error_cleanup (&error); /* FIXME don't raise here */
3714 * mono_property_get_value_checked:
3715 * \param prop \c MonoProperty to fetch
3716 * \param obj instance object on which to act
3717 * \param params parameters to pass to the propery
3718 * \param error set on error
3719 * Invokes the property's \c get method with the given arguments on the
3720 * object instance obj (or NULL for static properties).
3722 * If an exception is thrown, you can't use the
3723 * \c MonoObject* result from the function. The exception will be propagated via \p error.
3725 * \returns the value from invoking the get method on the property. On
3726 * failure returns NULL and sets \p error.
3729 mono_property_get_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3731 MONO_REQ_GC_UNSAFE_MODE;
3734 MonoObject *val = do_runtime_invoke (prop->get, obj, params, &exc, error);
3735 if (exc != NULL && !is_ok (error))
3736 mono_error_set_exception_instance (error, (MonoException*) exc);
3744 * mono_nullable_init:
3745 * @buf: The nullable structure to initialize.
3746 * @value: the value to initialize from
3747 * @klass: the type for the object
3749 * Initialize the nullable structure pointed to by @buf from @value which
3750 * should be a boxed value type. The size of @buf should be able to hold
3751 * as much data as the @klass->instance_size (which is the number of bytes
3752 * that will be copies).
3754 * Since Nullables have variable structure, we can not define a C
3755 * structure for them.
3758 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3760 MONO_REQ_GC_UNSAFE_MODE;
3762 MonoClass *param_class = klass->cast_class;
3764 mono_class_setup_fields (klass);
3765 g_assert (klass->fields_inited);
3767 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3768 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3770 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3772 if (param_class->has_references)
3773 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3775 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3777 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3782 * mono_nullable_init_from_handle:
3783 * @buf: The nullable structure to initialize.
3784 * @value: the value to initialize from
3785 * @klass: the type for the object
3787 * Initialize the nullable structure pointed to by @buf from @value which
3788 * should be a boxed value type. The size of @buf should be able to hold
3789 * as much data as the @klass->instance_size (which is the number of bytes
3790 * that will be copies).
3792 * Since Nullables have variable structure, we can not define a C
3793 * structure for them.
3796 mono_nullable_init_from_handle (guint8 *buf, MonoObjectHandle value, MonoClass *klass)
3798 MONO_REQ_GC_UNSAFE_MODE;
3800 MonoClass *param_class = klass->cast_class;
3802 mono_class_setup_fields (klass);
3803 g_assert (klass->fields_inited);
3805 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3806 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3808 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = MONO_HANDLE_IS_NULL (value) ? 0 : 1;
3809 if (!MONO_HANDLE_IS_NULL (value)) {
3810 uint32_t value_gchandle = 0;
3811 gpointer src = mono_object_handle_pin_unbox (value, &value_gchandle);
3812 if (param_class->has_references)
3813 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), src, 1, param_class);
3815 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), src, mono_class_value_size (param_class, NULL));
3816 mono_gchandle_free (value_gchandle);
3818 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3825 * mono_nullable_box:
3826 * \param buf The buffer representing the data to be boxed
3827 * \param klass the type to box it as.
3828 * \param error set on error
3830 * Creates a boxed vtype or NULL from the \c Nullable structure pointed to by
3831 * \p buf. On failure returns NULL and sets \p error.
3834 mono_nullable_box (guint8 *buf, MonoClass *klass, MonoError *error)
3836 MONO_REQ_GC_UNSAFE_MODE;
3839 MonoClass *param_class = klass->cast_class;
3841 mono_class_setup_fields (klass);
3842 g_assert (klass->fields_inited);
3844 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3845 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3847 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3848 MonoObject *o = mono_object_new_checked (mono_domain_get (), param_class, error);
3849 return_val_if_nok (error, NULL);
3850 if (param_class->has_references)
3851 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3853 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3861 * mono_get_delegate_invoke:
3862 * \param klass The delegate class
3863 * \returns the \c MonoMethod for the \c Invoke method in the delegate class or NULL if \p klass is a broken delegate type
3866 mono_get_delegate_invoke (MonoClass *klass)
3868 MONO_REQ_GC_NEUTRAL_MODE;
3872 /* This is called at runtime, so avoid the slower search in metadata */
3873 mono_class_setup_methods (klass);
3874 if (mono_class_has_failure (klass))
3876 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3881 * mono_get_delegate_begin_invoke:
3882 * \param klass The delegate class
3883 * \returns the \c MonoMethod for the \c BeginInvoke method in the delegate class or NULL if \p klass is a broken delegate type
3886 mono_get_delegate_begin_invoke (MonoClass *klass)
3888 MONO_REQ_GC_NEUTRAL_MODE;
3892 /* This is called at runtime, so avoid the slower search in metadata */
3893 mono_class_setup_methods (klass);
3894 if (mono_class_has_failure (klass))
3896 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3901 * mono_get_delegate_end_invoke:
3902 * \param klass The delegate class
3903 * \returns the \c MonoMethod for the \c EndInvoke method in the delegate class or NULL if \p klass is a broken delegate type
3906 mono_get_delegate_end_invoke (MonoClass *klass)
3908 MONO_REQ_GC_NEUTRAL_MODE;
3912 /* This is called at runtime, so avoid the slower search in metadata */
3913 mono_class_setup_methods (klass);
3914 if (mono_class_has_failure (klass))
3916 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3921 * mono_runtime_delegate_invoke:
3922 * \param delegate pointer to a delegate object.
3923 * \param params parameters for the delegate.
3924 * \param exc Pointer to the exception result.
3926 * Invokes the delegate method \p delegate with the parameters provided.
3928 * You can pass NULL as the \p exc argument if you don't want to
3929 * catch exceptions, otherwise, \c *exc will be set to the exception
3930 * thrown, if any. if an exception is thrown, you can't use the
3931 * \c MonoObject* result from the function.
3934 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3936 MONO_REQ_GC_UNSAFE_MODE;
3940 MonoObject *result = mono_runtime_delegate_try_invoke (delegate, params, exc, &error);
3942 mono_error_cleanup (&error);
3945 if (!is_ok (&error))
3946 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
3950 MonoObject *result = mono_runtime_delegate_invoke_checked (delegate, params, &error);
3951 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
3957 * mono_runtime_delegate_try_invoke:
3958 * \param delegate pointer to a delegate object.
3959 * \param params parameters for the delegate.
3960 * \param exc Pointer to the exception result.
3961 * \param error set on error
3962 * Invokes the delegate method \p delegate with the parameters provided.
3964 * You can pass NULL as the \p exc argument if you don't want to
3965 * catch exceptions, otherwise, \c *exc will be set to the exception
3966 * thrown, if any. On failure to execute, \p error will be set.
3967 * if an exception is thrown, you can't use the
3968 * \c MonoObject* result from the function.
3971 mono_runtime_delegate_try_invoke (MonoObject *delegate, void **params, MonoObject **exc, MonoError *error)
3973 MONO_REQ_GC_UNSAFE_MODE;
3977 MonoClass *klass = delegate->vtable->klass;
3980 im = mono_get_delegate_invoke (klass);
3982 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3985 o = mono_runtime_try_invoke (im, delegate, params, exc, error);
3987 o = mono_runtime_invoke_checked (im, delegate, params, error);
3994 * mono_runtime_delegate_invoke_checked:
3995 * \param delegate pointer to a delegate object.
3996 * \param params parameters for the delegate.
3997 * \param error set on error
3998 * Invokes the delegate method \p delegate with the parameters provided.
3999 * On failure \p error will be set and you can't use the \c MonoObject*
4000 * result from the function.
4003 mono_runtime_delegate_invoke_checked (MonoObject *delegate, void **params, MonoError *error)
4006 return mono_runtime_delegate_try_invoke (delegate, params, NULL, error);
4009 static char **main_args = NULL;
4010 static int num_main_args = 0;
4013 * mono_runtime_get_main_args:
4014 * \returns A \c MonoArray with the arguments passed to the main program
4017 mono_runtime_get_main_args (void)
4019 MONO_REQ_GC_UNSAFE_MODE;
4021 MonoArray *result = mono_runtime_get_main_args_checked (&error);
4022 mono_error_assert_ok (&error);
4027 * mono_runtime_get_main_args_checked:
4028 * \param error set on error
4029 * \returns a \c MonoArray with the arguments passed to the main
4030 * program. On failure returns NULL and sets \p error.
4033 mono_runtime_get_main_args_checked (MonoError *error)
4037 MonoDomain *domain = mono_domain_get ();
4041 res = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, num_main_args, error);
4042 return_val_if_nok (error, NULL);
4044 for (i = 0; i < num_main_args; ++i) {
4045 MonoString *arg = mono_string_new_checked (domain, main_args [i], error);
4046 return_val_if_nok (error, NULL);
4047 mono_array_setref (res, i, arg);
4054 free_main_args (void)
4056 MONO_REQ_GC_NEUTRAL_MODE;
4060 for (i = 0; i < num_main_args; ++i)
4061 g_free (main_args [i]);
4068 * mono_runtime_set_main_args:
4069 * \param argc number of arguments from the command line
4070 * \param argv array of strings from the command line
4071 * Set the command line arguments from an embedding application that doesn't otherwise call
4072 * \c mono_runtime_run_main.
4075 mono_runtime_set_main_args (int argc, char* argv[])
4077 MONO_REQ_GC_NEUTRAL_MODE;
4082 main_args = g_new0 (char*, argc);
4083 num_main_args = argc;
4085 for (i = 0; i < argc; ++i) {
4088 utf8_arg = mono_utf8_from_external (argv[i]);
4089 if (utf8_arg == NULL) {
4090 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
4091 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4095 main_args [i] = utf8_arg;
4102 * Prepare an array of arguments in order to execute a standard Main()
4103 * method (argc/argv contains the executable name). This method also
4104 * sets the command line argument value needed by System.Environment.
4108 prepare_run_main (MonoMethod *method, int argc, char *argv[])
4110 MONO_REQ_GC_UNSAFE_MODE;
4114 MonoArray *args = NULL;
4115 MonoDomain *domain = mono_domain_get ();
4116 gchar *utf8_fullpath;
4117 MonoMethodSignature *sig;
4119 g_assert (method != NULL);
4121 mono_thread_set_main (mono_thread_current ());
4123 main_args = g_new0 (char*, argc);
4124 num_main_args = argc;
4126 if (!g_path_is_absolute (argv [0])) {
4127 gchar *basename = g_path_get_basename (argv [0]);
4128 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
4132 utf8_fullpath = mono_utf8_from_external (fullpath);
4133 if(utf8_fullpath == NULL) {
4134 /* Printing the arg text will cause glib to
4135 * whinge about "Invalid UTF-8", but at least
4136 * its relevant, and shows the problem text
4139 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
4140 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4147 utf8_fullpath = mono_utf8_from_external (argv[0]);
4148 if(utf8_fullpath == NULL) {
4149 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
4150 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4155 main_args [0] = utf8_fullpath;
4157 for (i = 1; i < argc; ++i) {
4160 utf8_arg=mono_utf8_from_external (argv[i]);
4161 if(utf8_arg==NULL) {
4162 /* Ditto the comment about Invalid UTF-8 here */
4163 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
4164 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4168 main_args [i] = utf8_arg;
4173 sig = mono_method_signature (method);
4175 g_print ("Unable to load Main method.\n");
4179 if (sig->param_count) {
4180 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, argc, &error);
4181 mono_error_assert_ok (&error);
4182 for (i = 0; i < argc; ++i) {
4183 /* The encodings should all work, given that
4184 * we've checked all these args for the
4187 gchar *str = mono_utf8_from_external (argv [i]);
4188 MonoString *arg = mono_string_new_checked (domain, str, &error);
4189 mono_error_assert_ok (&error);
4190 mono_array_setref (args, i, arg);
4194 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, 0, &error);
4195 mono_error_assert_ok (&error);
4198 mono_assembly_set_main (method->klass->image->assembly);
4204 * mono_runtime_run_main:
4205 * \param method the method to start the application with (usually <code>Main</code>)
4206 * \param argc number of arguments from the command line
4207 * \param argv array of strings from the command line
4208 * \param exc excetption results
4209 * Execute a standard \c Main method (\p argc / \p argv contains the
4210 * executable name). This method also sets the command line argument value
4211 * needed by \c System.Environment.
4214 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
4217 MONO_REQ_GC_UNSAFE_MODE;
4220 MonoArray *args = prepare_run_main (method, argc, argv);
4223 res = mono_runtime_try_exec_main (method, args, exc);
4225 res = mono_runtime_exec_main_checked (method, args, &error);
4226 mono_error_raise_exception (&error); /* OK to throw, external only without a better alternative */
4232 * mono_runtime_run_main_checked:
4233 * \param method the method to start the application with (usually \c Main)
4234 * \param argc number of arguments from the command line
4235 * \param argv array of strings from the command line
4236 * \param error set on error
4238 * Execute a standard \c Main method (\p argc / \p argv contains the
4239 * executable name). This method also sets the command line argument value
4240 * needed by \c System.Environment. On failure sets \p error.
4243 mono_runtime_run_main_checked (MonoMethod *method, int argc, char* argv[],
4247 MonoArray *args = prepare_run_main (method, argc, argv);
4248 return mono_runtime_exec_main_checked (method, args, error);
4252 * mono_runtime_try_run_main:
4253 * \param method the method to start the application with (usually \c Main)
4254 * \param argc number of arguments from the command line
4255 * \param argv array of strings from the command line
4256 * \param exc set if \c Main throws an exception
4257 * \param error set if \c Main can't be executed
4258 * Execute a standard \c Main method (\p argc / \p argv contains the executable
4259 * name). This method also sets the command line argument value needed
4260 * by \c System.Environment. On failure sets \p error if Main can't be
4261 * executed or \p exc if it threw an exception.
4264 mono_runtime_try_run_main (MonoMethod *method, int argc, char* argv[],
4268 MonoArray *args = prepare_run_main (method, argc, argv);
4269 return mono_runtime_try_exec_main (method, args, exc);
4274 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4276 static MonoMethod *serialize_method;
4282 if (!serialize_method) {
4283 MonoClass *klass = mono_class_get_remoting_services_class ();
4284 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
4287 if (!serialize_method) {
4292 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
4297 array = mono_runtime_try_invoke (serialize_method, NULL, params, exc, &error);
4298 if (*exc == NULL && !mono_error_ok (&error))
4299 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert serialize_object to MonoError */
4301 mono_error_cleanup (&error);
4310 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4312 MONO_REQ_GC_UNSAFE_MODE;
4314 static MonoMethod *deserialize_method;
4320 if (!deserialize_method) {
4321 MonoClass *klass = mono_class_get_remoting_services_class ();
4322 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
4324 if (!deserialize_method) {
4332 result = mono_runtime_try_invoke (deserialize_method, NULL, params, exc, &error);
4333 if (*exc == NULL && !mono_error_ok (&error))
4334 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert deserialize_object to MonoError */
4336 mono_error_cleanup (&error);
4344 #ifndef DISABLE_REMOTING
4346 make_transparent_proxy (MonoObject *obj, MonoError *error)
4348 MONO_REQ_GC_UNSAFE_MODE;
4350 static MonoMethod *get_proxy_method;
4352 MonoDomain *domain = mono_domain_get ();
4353 MonoRealProxy *real_proxy;
4354 MonoReflectionType *reflection_type;
4355 MonoTransparentProxy *transparent_proxy;
4359 if (!get_proxy_method)
4360 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
4362 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
4364 real_proxy = (MonoRealProxy*) mono_object_new_checked (domain, mono_defaults.real_proxy_class, error);
4365 return_val_if_nok (error, NULL);
4366 reflection_type = mono_type_get_object_checked (domain, &obj->vtable->klass->byval_arg, error);
4367 return_val_if_nok (error, NULL);
4369 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
4370 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
4372 MonoObject *exc = NULL;
4374 transparent_proxy = (MonoTransparentProxy*) mono_runtime_try_invoke (get_proxy_method, real_proxy, NULL, &exc, error);
4375 if (exc != NULL && is_ok (error))
4376 mono_error_set_exception_instance (error, (MonoException*)exc);
4378 return (MonoObject*) transparent_proxy;
4380 #endif /* DISABLE_REMOTING */
4383 * mono_object_xdomain_representation
4384 * \param obj an object
4385 * \param target_domain a domain
4386 * \param error set on error.
4387 * Creates a representation of obj in the domain \p target_domain. This
4388 * is either a copy of \p obj arrived through via serialization and
4389 * deserialization or a proxy, depending on whether the object is
4390 * serializable or marshal by ref. \p obj must not be in \p target_domain.
4391 * If the object cannot be represented in \p target_domain, NULL is
4392 * returned and \p error is set appropriately.
4395 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoError *error)
4397 MONO_REQ_GC_UNSAFE_MODE;
4400 MonoObject *deserialized = NULL;
4402 #ifndef DISABLE_REMOTING
4403 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
4404 deserialized = make_transparent_proxy (obj, error);
4409 gboolean failure = FALSE;
4410 MonoDomain *domain = mono_domain_get ();
4411 MonoObject *serialized;
4412 MonoObject *exc = NULL;
4414 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
4415 serialized = serialize_object (obj, &failure, &exc);
4416 mono_domain_set_internal_with_options (target_domain, FALSE);
4418 deserialized = deserialize_object (serialized, &failure, &exc);
4419 if (domain != target_domain)
4420 mono_domain_set_internal_with_options (domain, FALSE);
4422 mono_error_set_exception_instance (error, (MonoException*)exc);
4425 return deserialized;
4428 /* Used in call_unhandled_exception_delegate */
4430 create_unhandled_exception_eventargs (MonoObject *exc, MonoError *error)
4432 MONO_REQ_GC_UNSAFE_MODE;
4437 MonoMethod *method = NULL;
4438 MonoBoolean is_terminating = TRUE;
4441 klass = mono_class_get_unhandled_exception_event_args_class ();
4442 mono_class_init (klass);
4444 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4445 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
4449 args [1] = &is_terminating;
4451 obj = mono_object_new_checked (mono_domain_get (), klass, error);
4452 return_val_if_nok (error, NULL);
4454 mono_runtime_invoke_checked (method, obj, args, error);
4455 return_val_if_nok (error, NULL);
4460 /* Used in mono_unhandled_exception */
4462 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4463 MONO_REQ_GC_UNSAFE_MODE;
4466 MonoObject *e = NULL;
4468 MonoDomain *current_domain = mono_domain_get ();
4470 if (domain != current_domain)
4471 mono_domain_set_internal_with_options (domain, FALSE);
4473 g_assert (domain == mono_object_domain (domain->domain));
4475 if (mono_object_domain (exc) != domain) {
4477 exc = mono_object_xdomain_representation (exc, domain, &error);
4479 if (!is_ok (&error)) {
4480 MonoError inner_error;
4481 MonoException *serialization_exc = mono_error_convert_to_exception (&error);
4482 exc = mono_object_xdomain_representation ((MonoObject*)serialization_exc, domain, &inner_error);
4483 mono_error_assert_ok (&inner_error);
4485 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4486 "System.Runtime.Serialization", "SerializationException",
4487 "Could not serialize unhandled exception.");
4491 g_assert (mono_object_domain (exc) == domain);
4493 pa [0] = domain->domain;
4494 pa [1] = create_unhandled_exception_eventargs (exc, &error);
4495 mono_error_assert_ok (&error);
4496 mono_runtime_delegate_try_invoke (delegate, pa, &e, &error);
4497 if (!is_ok (&error)) {
4499 e = (MonoObject*)mono_error_convert_to_exception (&error);
4501 mono_error_cleanup (&error);
4504 if (domain != current_domain)
4505 mono_domain_set_internal_with_options (current_domain, FALSE);
4508 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4509 if (!mono_error_ok (&error)) {
4510 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4511 mono_error_cleanup (&error);
4513 g_warning ("exception inside UnhandledException handler: %s\n", msg);
4519 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4522 * mono_runtime_unhandled_exception_policy_set:
4523 * \param policy the new policy
4524 * This is a VM internal routine.
4525 * Sets the runtime policy for handling unhandled exceptions.
4528 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4529 runtime_unhandled_exception_policy = policy;
4533 * mono_runtime_unhandled_exception_policy_get:
4535 * This is a VM internal routine.
4537 * Gets the runtime policy for handling unhandled exceptions.
4539 MonoRuntimeUnhandledExceptionPolicy
4540 mono_runtime_unhandled_exception_policy_get (void) {
4541 return runtime_unhandled_exception_policy;
4545 * mono_unhandled_exception:
4546 * \param exc exception thrown
4547 * This is a VM internal routine.
4549 * We call this function when we detect an unhandled exception
4550 * in the default domain.
4552 * It invokes the \c UnhandledException event in \c AppDomain or prints
4553 * a warning to the console
4556 mono_unhandled_exception (MonoObject *exc_raw)
4559 HANDLE_FUNCTION_ENTER ();
4560 MONO_HANDLE_DCL (MonoObject, exc);
4561 error_init (&error);
4562 mono_unhandled_exception_checked (exc, &error);
4563 mono_error_assert_ok (&error);
4564 HANDLE_FUNCTION_RETURN ();
4568 * mono_unhandled_exception:
4569 * @exc: exception thrown
4571 * This is a VM internal routine.
4573 * We call this function when we detect an unhandled exception
4574 * in the default domain.
4576 * It invokes the * UnhandledException event in AppDomain or prints
4577 * a warning to the console
4580 mono_unhandled_exception_checked (MonoObjectHandle exc, MonoError *error)
4582 MONO_REQ_GC_UNSAFE_MODE;
4585 MonoClassField *field;
4586 MonoDomain *current_domain, *root_domain;
4587 MonoObjectHandle current_appdomain_delegate = MONO_HANDLE_NEW (MonoObject, NULL);
4589 MonoClass *klass = mono_handle_class (exc);
4590 if (mono_class_has_parent (klass, mono_defaults.threadabortexception_class))
4593 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4596 current_domain = mono_domain_get ();
4597 root_domain = mono_get_root_domain ();
4599 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 */
4600 return_if_nok (error);
4601 if (current_domain != root_domain) {
4602 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 */
4603 return_if_nok (error);
4606 if (MONO_HANDLE_IS_NULL (current_appdomain_delegate) && MONO_HANDLE_IS_NULL (root_appdomain_delegate)) {
4607 mono_print_unhandled_exception (MONO_HANDLE_RAW (exc)); /* FIXME use handles for mono_print_unhandled_exception */
4609 /* unhandled exception callbacks must not be aborted */
4610 mono_threads_begin_abort_protected_block ();
4611 if (!MONO_HANDLE_IS_NULL (root_appdomain_delegate))
4612 call_unhandled_exception_delegate (root_domain, MONO_HANDLE_RAW (root_appdomain_delegate), MONO_HANDLE_RAW (exc)); /* FIXME use handles in call_unhandled_exception_delegate */
4613 if (!MONO_HANDLE_IS_NULL (current_appdomain_delegate))
4614 call_unhandled_exception_delegate (current_domain, MONO_HANDLE_RAW (current_appdomain_delegate), MONO_HANDLE_RAW (exc));
4615 mono_threads_end_abort_protected_block ();
4618 /* set exitcode only if we will abort the process */
4619 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4620 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4622 mono_environment_exitcode_set (1);
4627 * mono_runtime_exec_managed_code:
4628 * \param domain Application domain
4629 * \param main_func function to invoke from the execution thread
4630 * \param main_args parameter to the main_func
4631 * Launch a new thread to execute a function
4633 * \p main_func is called back from the thread with main_args as the
4634 * parameter. The callback function is expected to start \c Main
4635 * eventually. This function then waits for all managed threads to
4637 * It is not necessary anymore to execute managed code in a subthread,
4638 * so this function should not be used anymore by default: just
4639 * execute the code and then call mono_thread_manage().
4642 mono_runtime_exec_managed_code (MonoDomain *domain,
4643 MonoMainThreadFunc main_func,
4647 mono_thread_create_checked (domain, main_func, main_args, &error);
4648 mono_error_assert_ok (&error);
4650 mono_thread_manage ();
4654 prepare_thread_to_exec_main (MonoDomain *domain, MonoMethod *method)
4656 MonoInternalThread* thread = mono_thread_internal_current ();
4657 MonoCustomAttrInfo* cinfo;
4658 gboolean has_stathread_attribute;
4660 if (!domain->entry_assembly) {
4663 MonoAssembly *assembly;
4665 assembly = method->klass->image->assembly;
4666 domain->entry_assembly = assembly;
4667 /* Domains created from another domain already have application_base and configuration_file set */
4668 if (domain->setup->application_base == NULL) {
4669 MonoString *basedir = mono_string_new_checked (domain, assembly->basedir, &error);
4670 mono_error_assert_ok (&error);
4671 MONO_OBJECT_SETREF (domain->setup, application_base, basedir);
4674 if (domain->setup->configuration_file == NULL) {
4675 str = g_strconcat (assembly->image->name, ".config", NULL);
4676 MonoString *config_file = mono_string_new_checked (domain, str, &error);
4677 mono_error_assert_ok (&error);
4678 MONO_OBJECT_SETREF (domain->setup, configuration_file, config_file);
4680 mono_domain_set_options_from_config (domain);
4684 MonoError cattr_error;
4685 cinfo = mono_custom_attrs_from_method_checked (method, &cattr_error);
4686 mono_error_cleanup (&cattr_error); /* FIXME warn here? */
4688 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, mono_class_get_sta_thread_attribute_class ());
4690 mono_custom_attrs_free (cinfo);
4692 has_stathread_attribute = FALSE;
4694 if (has_stathread_attribute) {
4695 thread->apartment_state = ThreadApartmentState_STA;
4697 thread->apartment_state = ThreadApartmentState_MTA;
4699 mono_thread_init_apartment_state ();
4704 do_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4706 MONO_REQ_GC_UNSAFE_MODE;
4716 /* FIXME: check signature of method */
4717 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4719 res = mono_runtime_invoke_checked (method, NULL, pa, error);
4721 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4724 mono_environment_exitcode_set (rval);
4726 mono_runtime_invoke_checked (method, NULL, pa, error);
4738 do_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4740 MONO_REQ_GC_UNSAFE_MODE;
4750 /* FIXME: check signature of method */
4751 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4752 MonoError inner_error;
4754 res = mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4755 if (*exc == NULL && !mono_error_ok (&inner_error))
4756 *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4758 mono_error_cleanup (&inner_error);
4761 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4765 mono_environment_exitcode_set (rval);
4767 MonoError inner_error;
4768 mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4769 if (*exc == NULL && !mono_error_ok (&inner_error))
4770 *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4772 mono_error_cleanup (&inner_error);
4777 /* If the return type of Main is void, only
4778 * set the exitcode if an exception was thrown
4779 * (we don't want to blow away an
4780 * explicitly-set exit code)
4783 mono_environment_exitcode_set (rval);
4791 * Execute a standard Main() method (args doesn't contain the
4795 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4798 prepare_thread_to_exec_main (mono_object_domain (args), method);
4800 int rval = do_try_exec_main (method, args, exc);
4803 int rval = do_exec_main_checked (method, args, &error);
4804 mono_error_raise_exception (&error); /* OK to throw, external only with no better option */
4810 * Execute a standard Main() method (args doesn't contain the
4813 * On failure sets @error
4816 mono_runtime_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4819 prepare_thread_to_exec_main (mono_object_domain (args), method);
4820 return do_exec_main_checked (method, args, error);
4824 * Execute a standard Main() method (args doesn't contain the
4827 * On failure sets @error if Main couldn't be executed, or @exc if it threw an exception.
4830 mono_runtime_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4832 prepare_thread_to_exec_main (mono_object_domain (args), method);
4833 return do_try_exec_main (method, args, exc);
4838 /** invoke_array_extract_argument:
4839 * @params: array of arguments to the method.
4840 * @i: the index of the argument to extract.
4841 * @t: ith type from the method signature.
4842 * @has_byref_nullables: outarg - TRUE if method expects a byref nullable argument
4843 * @error: set on error.
4845 * Given an array of method arguments, return the ith one using the corresponding type
4846 * to perform necessary unboxing. If method expects a ref nullable argument, writes TRUE to @has_byref_nullables.
4848 * On failure sets @error and returns NULL.
4851 invoke_array_extract_argument (MonoArray *params, int i, MonoType *t, gboolean* has_byref_nullables, MonoError *error)
4853 MonoType *t_orig = t;
4854 gpointer result = NULL;
4860 case MONO_TYPE_BOOLEAN:
4863 case MONO_TYPE_CHAR:
4872 case MONO_TYPE_VALUETYPE:
4873 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (t_orig))) {
4874 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4875 result = mono_array_get (params, MonoObject*, i);
4877 *has_byref_nullables = TRUE;
4879 /* MS seems to create the objects if a null is passed in */
4880 gboolean was_null = FALSE;
4881 if (!mono_array_get (params, MonoObject*, i)) {
4882 MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (t_orig), error);
4883 return_val_if_nok (error, NULL);
4884 mono_array_setref (params, i, o);
4890 * We can't pass the unboxed vtype byref to the callee, since
4891 * that would mean the callee would be able to modify boxed
4892 * primitive types. So we (and MS) make a copy of the boxed
4893 * object, pass that to the callee, and replace the original
4894 * boxed object in the arg array with the copy.
4896 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4897 MonoObject *copy = mono_value_box_checked (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig), error);
4898 return_val_if_nok (error, NULL);
4899 mono_array_setref (params, i, copy);
4902 result = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4903 if (!t->byref && was_null)
4904 mono_array_setref (params, i, NULL);
4907 case MONO_TYPE_STRING:
4908 case MONO_TYPE_OBJECT:
4909 case MONO_TYPE_CLASS:
4910 case MONO_TYPE_ARRAY:
4911 case MONO_TYPE_SZARRAY:
4913 result = mono_array_addr (params, MonoObject*, i);
4914 // FIXME: I need to check this code path
4916 result = mono_array_get (params, MonoObject*, i);
4918 case MONO_TYPE_GENERICINST:
4920 t = &t->data.generic_class->container_class->this_arg;
4922 t = &t->data.generic_class->container_class->byval_arg;
4924 case MONO_TYPE_PTR: {
4927 /* The argument should be an IntPtr */
4928 arg = mono_array_get (params, MonoObject*, i);
4932 g_assert (arg->vtable->klass == mono_defaults.int_class);
4933 result = ((MonoIntPtr*)arg)->m_value;
4938 g_error ("type 0x%x not handled in mono_runtime_invoke_array", t_orig->type);
4943 * mono_runtime_invoke_array:
4944 * \param method method to invoke
4945 * \param obj object instance
4946 * \param params arguments to the method
4947 * \param exc exception information.
4948 * Invokes the method represented by \p method on the object \p obj.
4950 * \p obj is the \c this pointer, it should be NULL for static
4951 * methods, a \c MonoObject* for object instances and a pointer to
4952 * the value type for value types.
4954 * The \p params array contains the arguments to the method with the
4955 * same convention: \c MonoObject* pointers for object instances and
4956 * pointers to the value type otherwise. The \c _invoke_array
4957 * variant takes a C# \c object[] as the params argument (\c MonoArray*):
4958 * in this case the value types are boxed inside the
4959 * respective reference representation.
4961 * From unmanaged code you'll usually use the
4962 * mono_runtime_invoke_checked() variant.
4964 * Note that this function doesn't handle virtual methods for
4965 * you, it will exec the exact method you pass: we still need to
4966 * expose a function to lookup the derived class implementation
4967 * of a virtual method (there are examples of this in the code,
4970 * You can pass NULL as the \p exc argument if you don't want to
4971 * catch exceptions, otherwise, \c *exc will be set to the exception
4972 * thrown, if any. if an exception is thrown, you can't use the
4973 * \c MonoObject* result from the function.
4975 * If the method returns a value type, it is boxed in an object
4979 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4984 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, exc, &error);
4986 mono_error_cleanup (&error);
4989 if (!is_ok (&error))
4990 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
4994 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, NULL, &error);
4995 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
5001 * mono_runtime_invoke_array_checked:
5002 * \param method method to invoke
5003 * \param obj object instance
5004 * \param params arguments to the method
5005 * \param error set on failure.
5006 * Invokes the method represented by \p method on the object \p obj.
5008 * \p obj is the \c this pointer, it should be NULL for static
5009 * methods, a \c MonoObject* for object instances and a pointer to
5010 * the value type for value types.
5012 * The \p params array contains the arguments to the method with the
5013 * same convention: \c MonoObject* pointers for object instances and
5014 * pointers to the value type otherwise. The \c _invoke_array
5015 * variant takes a C# \c object[] as the \p params argument (\c MonoArray*):
5016 * in this case the value types are boxed inside the
5017 * respective reference representation.
5019 * From unmanaged code you'll usually use the
5020 * mono_runtime_invoke_checked() variant.
5022 * Note that this function doesn't handle virtual methods for
5023 * you, it will exec the exact method you pass: we still need to
5024 * expose a function to lookup the derived class implementation
5025 * of a virtual method (there are examples of this in the code,
5028 * On failure or exception, \p error will be set. In that case, you
5029 * can't use the \c MonoObject* result from the function.
5031 * If the method returns a value type, it is boxed in an object
5035 mono_runtime_invoke_array_checked (MonoMethod *method, void *obj, MonoArray *params,
5039 return mono_runtime_try_invoke_array (method, obj, params, NULL, error);
5043 * mono_runtime_try_invoke_array:
5044 * \param method method to invoke
5045 * \param obj object instance
5046 * \param params arguments to the method
5047 * \param exc exception information.
5048 * \param error set on failure.
5049 * Invokes the method represented by \p method on the object \p obj.
5051 * \p obj is the \c this pointer, it should be NULL for static
5052 * methods, a \c MonoObject* for object instances and a pointer to
5053 * the value type for value types.
5055 * The \p params array contains the arguments to the method with the
5056 * same convention: \c MonoObject* pointers for object instances and
5057 * pointers to the value type otherwise. The \c _invoke_array
5058 * variant takes a C# \c object[] as the params argument (\c MonoArray*):
5059 * in this case the value types are boxed inside the
5060 * respective reference representation.
5062 * From unmanaged code you'll usually use the
5063 * mono_runtime_invoke_checked() variant.
5065 * Note that this function doesn't handle virtual methods for
5066 * you, it will exec the exact method you pass: we still need to
5067 * expose a function to lookup the derived class implementation
5068 * of a virtual method (there are examples of this in the code,
5071 * You can pass NULL as the \p exc argument if you don't want to catch
5072 * exceptions, otherwise, \c *exc will be set to the exception thrown, if
5073 * any. On other failures, \p error will be set. If an exception is
5074 * thrown or there's an error, you can't use the \c MonoObject* result
5075 * from the function.
5077 * If the method returns a value type, it is boxed in an object
5081 mono_runtime_try_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
5082 MonoObject **exc, MonoError *error)
5084 MONO_REQ_GC_UNSAFE_MODE;
5088 MonoMethodSignature *sig = mono_method_signature (method);
5089 gpointer *pa = NULL;
5092 gboolean has_byref_nullables = FALSE;
5094 if (NULL != params) {
5095 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
5096 for (i = 0; i < mono_array_length (params); i++) {
5097 MonoType *t = sig->params [i];
5098 pa [i] = invoke_array_extract_argument (params, i, t, &has_byref_nullables, error);
5099 return_val_if_nok (error, NULL);
5103 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
5106 if (mono_class_is_nullable (method->klass)) {
5107 /* Need to create a boxed vtype instead */
5113 return mono_value_box_checked (mono_domain_get (), method->klass->cast_class, pa [0], error);
5118 obj = mono_object_new_checked (mono_domain_get (), method->klass, error);
5119 mono_error_assert_ok (error);
5120 g_assert (obj); /*maybe we should raise a TLE instead?*/
5121 #ifndef DISABLE_REMOTING
5122 if (mono_object_is_transparent_proxy (obj)) {
5123 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
5126 if (method->klass->valuetype)
5127 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
5130 } else if (method->klass->valuetype) {
5131 obj = mono_value_box_checked (mono_domain_get (), method->klass, obj, error);
5132 return_val_if_nok (error, NULL);
5136 mono_runtime_try_invoke (method, o, pa, exc, error);
5138 mono_runtime_invoke_checked (method, o, pa, error);
5141 return (MonoObject *)obj;
5143 if (mono_class_is_nullable (method->klass)) {
5144 MonoObject *nullable;
5146 /* Convert the unboxed vtype into a Nullable structure */
5147 nullable = mono_object_new_checked (mono_domain_get (), method->klass, error);
5148 return_val_if_nok (error, NULL);
5150 MonoObject *boxed = mono_value_box_checked (mono_domain_get (), method->klass->cast_class, obj, error);
5151 return_val_if_nok (error, NULL);
5152 mono_nullable_init ((guint8 *)mono_object_unbox (nullable), boxed, method->klass);
5153 obj = mono_object_unbox (nullable);
5156 /* obj must be already unboxed if needed */
5158 res = mono_runtime_try_invoke (method, obj, pa, exc, error);
5160 res = mono_runtime_invoke_checked (method, obj, pa, error);
5162 return_val_if_nok (error, NULL);
5164 if (sig->ret->type == MONO_TYPE_PTR) {
5165 MonoClass *pointer_class;
5166 static MonoMethod *box_method;
5168 MonoObject *box_exc;
5171 * The runtime-invoke wrapper returns a boxed IntPtr, need to
5172 * convert it to a Pointer object.
5174 pointer_class = mono_class_get_pointer_class ();
5176 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
5178 g_assert (res->vtable->klass == mono_defaults.int_class);
5179 box_args [0] = ((MonoIntPtr*)res)->m_value;
5180 box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, error);
5181 return_val_if_nok (error, NULL);
5183 res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, error);
5184 g_assert (box_exc == NULL);
5185 mono_error_assert_ok (error);
5188 if (has_byref_nullables) {
5190 * The runtime invoke wrapper already converted byref nullables back,
5191 * and stored them in pa, we just need to copy them back to the
5194 for (i = 0; i < mono_array_length (params); i++) {
5195 MonoType *t = sig->params [i];
5197 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
5198 mono_array_setref (params, i, pa [i]);
5208 * \param klass the class of the object that we want to create
5209 * \returns a newly created object whose definition is
5210 * looked up using \p klass. This will not invoke any constructors,
5211 * so the consumer of this routine has to invoke any constructors on
5212 * its own to initialize the object.
5214 * It returns NULL on failure.
5217 mono_object_new (MonoDomain *domain, MonoClass *klass)
5219 MONO_REQ_GC_UNSAFE_MODE;
5223 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5225 mono_error_cleanup (&error);
5230 ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
5232 MONO_REQ_GC_UNSAFE_MODE;
5236 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5238 mono_error_set_pending_exception (&error);
5243 * mono_object_new_checked:
5244 * \param klass the class of the object that we want to create
5245 * \param error set on error
5246 * \returns a newly created object whose definition is
5247 * looked up using \p klass. This will not invoke any constructors,
5248 * so the consumer of this routine has to invoke any constructors on
5249 * its own to initialize the object.
5251 * It returns NULL on failure and sets \p error.
5254 mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
5256 MONO_REQ_GC_UNSAFE_MODE;
5260 vtable = mono_class_vtable_full (domain, klass, error);
5264 MonoObject *o = mono_object_new_specific_checked (vtable, error);
5269 * mono_object_new_pinned:
5271 * Same as mono_object_new, but the returned object will be pinned.
5272 * For SGEN, these objects will only be freed at appdomain unload.
5275 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
5277 MONO_REQ_GC_UNSAFE_MODE;
5283 vtable = mono_class_vtable (domain, klass);
5284 g_assert (vtable); /* FIXME don't swallow the error */
5286 MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
5288 if (G_UNLIKELY (!o))
5289 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
5290 else if (G_UNLIKELY (vtable->klass->has_finalize))
5291 mono_object_register_finalizer (o);
5297 * mono_object_new_specific:
5298 * \param vtable the vtable of the object that we want to create
5299 * \returns A newly created object with class and domain specified
5303 mono_object_new_specific (MonoVTable *vtable)
5306 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5307 mono_error_cleanup (&error);
5313 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
5315 MONO_REQ_GC_UNSAFE_MODE;
5321 /* check for is_com_object for COM Interop */
5322 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
5325 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
5328 MonoClass *klass = mono_class_get_activation_services_class ();
5331 mono_class_init (klass);
5333 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
5335 mono_error_set_not_supported (error, "Linked away.");
5338 vtable->domain->create_proxy_for_type_method = im;
5341 pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
5342 if (!mono_error_ok (error))
5345 o = mono_runtime_invoke_checked (im, NULL, pa, error);
5346 if (!mono_error_ok (error))
5353 return mono_object_new_alloc_specific_checked (vtable, error);
5357 ves_icall_object_new_specific (MonoVTable *vtable)
5360 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5361 mono_error_set_pending_exception (&error);
5367 * mono_object_new_alloc_specific:
5368 * \param vtable virtual table for the object.
5369 * This function allocates a new \c MonoObject with the type derived
5370 * from the \p vtable information. If the class of this object has a
5371 * finalizer, then the object will be tracked for finalization.
5373 * This method might raise an exception on errors. Use the
5374 * \c mono_object_new_fast_checked method if you want to manually raise
5377 * \returns the allocated object.
5380 mono_object_new_alloc_specific (MonoVTable *vtable)
5383 MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
5384 mono_error_cleanup (&error);
5390 * mono_object_new_alloc_specific_checked:
5391 * \param vtable virtual table for the object.
5392 * \param error holds the error return value.
5394 * This function allocates a new \c MonoObject with the type derived
5395 * from the \p vtable information. If the class of this object has a
5396 * finalizer, then the object will be tracked for finalization.
5398 * If there is not enough memory, the \p error parameter will be set
5399 * and will contain a user-visible message with the amount of bytes
5400 * that were requested.
5402 * \returns the allocated object, or NULL if there is not enough memory
5405 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
5407 MONO_REQ_GC_UNSAFE_MODE;
5413 o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5415 if (G_UNLIKELY (!o))
5416 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5417 else if (G_UNLIKELY (vtable->klass->has_finalize))
5418 mono_object_register_finalizer (o);
5424 * mono_object_new_fast:
5425 * \param vtable virtual table for the object.
5427 * This function allocates a new \c MonoObject with the type derived
5428 * from the \p vtable information. The returned object is not tracked
5429 * for finalization. If your object implements a finalizer, you should
5430 * use \c mono_object_new_alloc_specific instead.
5432 * This method might raise an exception on errors. Use the
5433 * \c mono_object_new_fast_checked method if you want to manually raise
5436 * \returns the allocated object.
5439 mono_object_new_fast (MonoVTable *vtable)
5442 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5443 mono_error_cleanup (&error);
5449 * mono_object_new_fast_checked:
5450 * \param vtable virtual table for the object.
5451 * \param error holds the error return value.
5453 * This function allocates a new \c MonoObject with the type derived
5454 * from the \p vtable information. The returned object is not tracked
5455 * for finalization. If your object implements a finalizer, you should
5456 * use \c mono_object_new_alloc_specific_checked instead.
5458 * If there is not enough memory, the \p error parameter will be set
5459 * and will contain a user-visible message with the amount of bytes
5460 * that were requested.
5462 * \returns the allocated object, or NULL if there is not enough memory
5465 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
5467 MONO_REQ_GC_UNSAFE_MODE;
5473 o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5475 if (G_UNLIKELY (!o))
5476 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5482 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
5484 MONO_REQ_GC_UNSAFE_MODE;
5490 o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
5492 if (G_UNLIKELY (!o))
5493 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5494 else if (G_UNLIKELY (vtable->klass->has_finalize))
5495 mono_object_register_finalizer (o);
5501 * mono_object_new_from_token:
5502 * \param image Context where the type_token is hosted
5503 * \param token a token of the type that we want to create
5504 * \returns A newly created object whose definition is
5505 * looked up using \p token in the \p image image
5508 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
5510 MONO_REQ_GC_UNSAFE_MODE;
5516 klass = mono_class_get_checked (image, token, &error);
5517 mono_error_assert_ok (&error);
5519 result = mono_object_new_checked (domain, klass, &error);
5521 mono_error_cleanup (&error);
5528 * mono_object_clone:
5529 * \param obj the object to clone
5530 * \returns A newly created object who is a shallow copy of \p obj
5533 mono_object_clone (MonoObject *obj)
5536 MonoObject *o = mono_object_clone_checked (obj, &error);
5537 mono_error_cleanup (&error);
5543 mono_object_clone_checked (MonoObject *obj, MonoError *error)
5545 MONO_REQ_GC_UNSAFE_MODE;
5552 size = obj->vtable->klass->instance_size;
5554 if (obj->vtable->klass->rank)
5555 return (MonoObject*)mono_array_clone_checked ((MonoArray*)obj, error);
5557 o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
5559 if (G_UNLIKELY (!o)) {
5560 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5564 /* If the object doesn't contain references this will do a simple memmove. */
5565 mono_gc_wbarrier_object_copy (o, obj);
5567 if (obj->vtable->klass->has_finalize)
5568 mono_object_register_finalizer (o);
5573 * mono_array_full_copy:
5574 * \param src source array to copy
5575 * \param dest destination array
5576 * Copies the content of one array to another with exactly the same type and size.
5579 mono_array_full_copy (MonoArray *src, MonoArray *dest)
5581 MONO_REQ_GC_UNSAFE_MODE;
5584 MonoClass *klass = src->obj.vtable->klass;
5586 g_assert (klass == dest->obj.vtable->klass);
5588 size = mono_array_length (src);
5589 g_assert (size == mono_array_length (dest));
5590 size *= mono_array_element_size (klass);
5592 array_full_copy_unchecked_size (src, dest, klass, size);
5596 array_full_copy_unchecked_size (MonoArray *src, MonoArray *dest, MonoClass *klass, uintptr_t size)
5598 if (mono_gc_is_moving ()) {
5599 if (klass->element_class->valuetype) {
5600 if (klass->element_class->has_references)
5601 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
5603 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5605 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
5608 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5613 * mono_array_clone_in_domain:
5614 * \param domain the domain in which the array will be cloned into
5615 * \param array the array to clone
5616 * \param error set on error
5617 * This routine returns a copy of the array that is hosted on the
5618 * specified \c MonoDomain. On failure returns NULL and sets \p error.
5621 mono_array_clone_in_domain (MonoDomain *domain, MonoArrayHandle array_handle, MonoError *error)
5623 MONO_REQ_GC_UNSAFE_MODE;
5625 MonoArrayHandle result = MONO_HANDLE_NEW (MonoArray, NULL);
5627 MonoClass *klass = mono_handle_class (array_handle);
5631 /* Pin source array here - if bounds is non-NULL, it's a pointer into the object data */
5632 uint32_t src_handle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, array_handle), TRUE);
5634 MonoArrayBounds *array_bounds = MONO_HANDLE_GETVAL (array_handle, bounds);
5636 if (array_bounds == NULL) {
5637 size = mono_array_handle_length (array_handle);
5638 o = mono_array_new_full_handle (domain, klass, &size, NULL, error);
5641 size *= mono_array_element_size (klass);
5643 uintptr_t *sizes = (uintptr_t *)alloca (klass->rank * sizeof (uintptr_t));
5644 intptr_t *lower_bounds = (intptr_t *)alloca (klass->rank * sizeof (intptr_t));
5645 size = mono_array_element_size (klass);
5646 for (int i = 0; i < klass->rank; ++i) {
5647 sizes [i] = array_bounds [i].length;
5648 size *= array_bounds [i].length;
5649 lower_bounds [i] = array_bounds [i].lower_bound;
5651 o = mono_array_new_full_handle (domain, klass, sizes, lower_bounds, error);
5656 uint32_t dst_handle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, o), TRUE);
5657 array_full_copy_unchecked_size (MONO_HANDLE_RAW (array_handle), MONO_HANDLE_RAW (o), klass, size);
5658 mono_gchandle_free (dst_handle);
5660 MONO_HANDLE_ASSIGN (result, o);
5663 mono_gchandle_free (src_handle);
5669 * \param array the array to clone
5670 * \returns A newly created array who is a shallow copy of \p array
5673 mono_array_clone (MonoArray *array)
5675 MONO_REQ_GC_UNSAFE_MODE;
5678 MonoArray *result = mono_array_clone_checked (array, &error);
5679 mono_error_cleanup (&error);
5684 * mono_array_clone_checked:
5685 * \param array the array to clone
5686 * \param error set on error
5687 * \returns A newly created array who is a shallow copy of \p array. On
5688 * failure returns NULL and sets \p error.
5691 mono_array_clone_checked (MonoArray *array_raw, MonoError *error)
5693 MONO_REQ_GC_UNSAFE_MODE;
5694 HANDLE_FUNCTION_ENTER ();
5695 /* FIXME: callers of mono_array_clone_checked should use handles */
5697 MONO_HANDLE_DCL (MonoArray, array);
5698 MonoArrayHandle result = mono_array_clone_in_domain (MONO_HANDLE_DOMAIN (array), array, error);
5699 HANDLE_FUNCTION_RETURN_OBJ (result);
5702 /* helper macros to check for overflow when calculating the size of arrays */
5703 #ifdef MONO_BIG_ARRAYS
5704 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
5705 #define MYGUINT_MAX MYGUINT64_MAX
5706 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5707 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
5708 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5709 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
5710 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
5712 #define MYGUINT32_MAX 4294967295U
5713 #define MYGUINT_MAX MYGUINT32_MAX
5714 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5715 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
5716 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5717 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
5718 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
5722 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
5724 MONO_REQ_GC_NEUTRAL_MODE;
5728 byte_len = mono_array_element_size (klass);
5729 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
5732 if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
5734 byte_len += MONO_SIZEOF_MONO_ARRAY;
5742 * mono_array_new_full:
5743 * \param domain domain where the object is created
5744 * \param array_class array class
5745 * \param lengths lengths for each dimension in the array
5746 * \param lower_bounds lower bounds for each dimension in the array (may be NULL)
5747 * This routine creates a new array object with the given dimensions,
5748 * lower bounds and type.
5751 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
5754 MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
5755 mono_error_cleanup (&error);
5761 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
5763 MONO_REQ_GC_UNSAFE_MODE;
5765 uintptr_t byte_len = 0, len, bounds_size;
5768 MonoArrayBounds *bounds;
5774 if (!array_class->inited)
5775 mono_class_init (array_class);
5779 /* A single dimensional array with a 0 lower bound is the same as an szarray */
5780 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
5782 if (len > MONO_ARRAY_MAX_INDEX) {
5783 mono_error_set_generic_error (error, "System", "OverflowException", "");
5788 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
5790 for (i = 0; i < array_class->rank; ++i) {
5791 if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
5792 mono_error_set_generic_error (error, "System", "OverflowException", "");
5795 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5796 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5803 if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5804 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5810 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5811 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5814 byte_len = (byte_len + 3) & ~3;
5815 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5816 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5819 byte_len += bounds_size;
5822 * Following three lines almost taken from mono_object_new ():
5823 * they need to be kept in sync.
5825 vtable = mono_class_vtable_full (domain, array_class, error);
5826 return_val_if_nok (error, NULL);
5829 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5831 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5833 if (G_UNLIKELY (!o)) {
5834 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5838 array = (MonoArray*)o;
5840 bounds = array->bounds;
5843 for (i = 0; i < array_class->rank; ++i) {
5844 bounds [i].length = lengths [i];
5846 bounds [i].lower_bound = lower_bounds [i];
5855 * \param domain domain where the object is created
5856 * \param eclass element class
5857 * \param n number of array elements
5858 * This routine creates a new szarray with \p n elements of type \p eclass.
5861 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5863 MONO_REQ_GC_UNSAFE_MODE;
5866 MonoArray *result = mono_array_new_checked (domain, eclass, n, &error);
5867 mono_error_cleanup (&error);
5872 * mono_array_new_checked:
5873 * \param domain domain where the object is created
5874 * \param eclass element class
5875 * \param n number of array elements
5876 * \param error set on error
5877 * This routine creates a new szarray with \p n elements of type \p eclass.
5878 * On failure returns NULL and sets \p error.
5881 mono_array_new_checked (MonoDomain *domain, MonoClass *eclass, uintptr_t n, MonoError *error)
5887 ac = mono_array_class_get (eclass, 1);
5890 MonoVTable *vtable = mono_class_vtable_full (domain, ac, error);
5891 return_val_if_nok (error, NULL);
5893 return mono_array_new_specific_checked (vtable, n, error);
5897 ves_icall_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5900 MonoArray *arr = mono_array_new_checked (domain, eclass, n, &error);
5901 mono_error_set_pending_exception (&error);
5907 * mono_array_new_specific:
5908 * \param vtable a vtable in the appropriate domain for an initialized class
5909 * \param n number of array elements
5910 * This routine is a fast alternative to \c mono_array_new for code which
5911 * can be sure about the domain it operates in.
5914 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5917 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5918 mono_error_cleanup (&error);
5924 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
5926 MONO_REQ_GC_UNSAFE_MODE;
5933 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
5934 mono_error_set_generic_error (error, "System", "OverflowException", "");
5938 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
5939 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5942 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
5944 if (G_UNLIKELY (!o)) {
5945 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5949 return (MonoArray*)o;
5953 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
5956 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5957 mono_error_set_pending_exception (&error);
5963 * mono_string_empty_wrapper:
5965 * Returns: The same empty string instance as the managed string.Empty
5968 mono_string_empty_wrapper (void)
5970 MonoDomain *domain = mono_domain_get ();
5971 return mono_string_empty (domain);
5975 * mono_string_empty:
5977 * Returns: The same empty string instance as the managed string.Empty
5980 mono_string_empty (MonoDomain *domain)
5983 g_assert (domain->empty_string);
5984 return domain->empty_string;
5988 * mono_string_new_utf16:
5989 * \param text a pointer to an utf16 string
5990 * \param len the length of the string
5991 * \returns A newly created string object which contains \p text.
5994 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
5996 MONO_REQ_GC_UNSAFE_MODE;
5999 MonoString *res = NULL;
6000 res = mono_string_new_utf16_checked (domain, text, len, &error);
6001 mono_error_cleanup (&error);
6007 * mono_string_new_utf16_checked:
6008 * \param text a pointer to an utf16 string
6009 * \param len the length of the string
6010 * \param error written on error.
6011 * \returns A newly created string object which contains \p text.
6012 * On error, returns NULL and sets \p error.
6015 mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
6017 MONO_REQ_GC_UNSAFE_MODE;
6023 s = mono_string_new_size_checked (domain, len, error);
6025 memcpy (mono_string_chars (s), text, len * 2);
6031 * mono_string_new_utf16_handle:
6032 * \param text a pointer to an utf16 string
6033 * \param len the length of the string
6034 * \param error written on error.
6035 * \returns A newly created string object which contains \p text.
6036 * On error, returns NULL and sets \p error.
6039 mono_string_new_utf16_handle (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
6041 return MONO_HANDLE_NEW (MonoString, mono_string_new_utf16_checked (domain, text, len, error));
6045 * mono_string_new_utf32_checked:
6046 * \param text a pointer to an utf32 string
6047 * \param len the length of the string
6048 * \param error set on failure.
6049 * \returns A newly created string object which contains \p text. On failure returns NULL and sets \p error.
6052 mono_string_new_utf32_checked (MonoDomain *domain, const mono_unichar4 *text, gint32 len, MonoError *error)
6054 MONO_REQ_GC_UNSAFE_MODE;
6057 mono_unichar2 *utf16_output = NULL;
6058 gint32 utf16_len = 0;
6059 GError *gerror = NULL;
6060 glong items_written;
6063 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
6066 g_error_free (gerror);
6068 while (utf16_output [utf16_len]) utf16_len++;
6070 s = mono_string_new_size_checked (domain, utf16_len, error);
6071 return_val_if_nok (error, NULL);
6073 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
6075 g_free (utf16_output);
6081 * mono_string_new_utf32:
6082 * \param text a pointer to a UTF-32 string
6083 * \param len the length of the string
6084 * \returns A newly created string object which contains \p text.
6087 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
6090 MonoString *result = mono_string_new_utf32_checked (domain, text, len, &error);
6091 mono_error_cleanup (&error);
6096 * mono_string_new_size:
6097 * \param text a pointer to a UTF-16 string
6098 * \param len the length of the string
6099 * \returns A newly created string object of \p len
6102 mono_string_new_size (MonoDomain *domain, gint32 len)
6105 MonoString *str = mono_string_new_size_checked (domain, len, &error);
6106 mono_error_cleanup (&error);
6112 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
6114 MONO_REQ_GC_UNSAFE_MODE;
6122 /* check for overflow */
6123 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
6124 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
6128 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
6129 g_assert (size > 0);
6131 vtable = mono_class_vtable (domain, mono_defaults.string_class);
6134 s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
6136 if (G_UNLIKELY (!s)) {
6137 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", size);
6145 * mono_string_new_len:
6146 * \param text a pointer to an utf8 string
6147 * \param length number of bytes in \p text to consider
6148 * \returns A newly created string object which contains \p text.
6151 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
6153 MONO_REQ_GC_UNSAFE_MODE;
6156 MonoString *result = mono_string_new_len_checked (domain, text, length, &error);
6157 mono_error_cleanup (&error);
6162 * mono_string_new_len_checked:
6163 * \param text a pointer to an utf8 string
6164 * \param length number of bytes in \p text to consider
6165 * \param error set on error
6166 * \returns A newly created string object which contains \p text. On
6167 * failure returns NULL and sets \p error.
6170 mono_string_new_len_checked (MonoDomain *domain, const char *text, guint length, MonoError *error)
6172 MONO_REQ_GC_UNSAFE_MODE;
6176 GError *eg_error = NULL;
6177 MonoString *o = NULL;
6179 glong items_written;
6181 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
6184 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6186 g_error_free (eg_error);
6195 * \param text a pointer to a UTF-8 string
6196 * \deprecated Use \c mono_string_new_checked in new code.
6197 * This function asserts if it cannot allocate a new string.
6198 * \returns A newly created string object which contains \p text.
6201 mono_string_new (MonoDomain *domain, const char *text)
6204 MonoString *res = NULL;
6205 res = mono_string_new_checked (domain, text, &error);
6206 mono_error_assert_ok (&error);
6211 * mono_string_new_checked:
6212 * \param text a pointer to an utf8 string
6213 * \param merror set on error
6214 * \returns A newly created string object which contains \p text.
6215 * On error returns NULL and sets \p merror.
6218 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
6220 MONO_REQ_GC_UNSAFE_MODE;
6222 GError *eg_error = NULL;
6223 MonoString *o = NULL;
6225 glong items_written;
6232 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &eg_error);
6235 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6237 mono_error_set_execution_engine (error, "String conversion error: %s", eg_error->message);
6242 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
6247 MonoString *o = NULL;
6249 if (!g_utf8_validate (text, -1, &end)) {
6250 mono_error_set_argument (error, "text", "Not a valid utf8 string");
6254 len = g_utf8_strlen (text, -1);
6255 o = mono_string_new_size_checked (domain, len, error);
6258 str = mono_string_chars (o);
6260 while (text < end) {
6261 *str++ = g_utf8_get_char (text);
6262 text = g_utf8_next_char (text);
6271 * mono_string_new_wrapper:
6272 * \param text pointer to UTF-8 characters.
6273 * Helper function to create a string object from \p text in the current domain.
6276 mono_string_new_wrapper (const char *text)
6278 MONO_REQ_GC_UNSAFE_MODE;
6280 MonoDomain *domain = mono_domain_get ();
6284 MonoString *result = mono_string_new_checked (domain, text, &error);
6285 mono_error_assert_ok (&error);
6294 * \param class the class of the value
6295 * \param value a pointer to the unboxed data
6296 * \returns A newly created object which contains \p value.
6299 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
6302 MonoObject *result = mono_value_box_checked (domain, klass, value, &error);
6303 mono_error_cleanup (&error);
6308 * mono_value_box_checked:
6309 * \param domain the domain of the new object
6310 * \param class the class of the value
6311 * \param value a pointer to the unboxed data
6312 * \param error set on error
6313 * \returns A newly created object which contains \p value. On failure
6314 * returns NULL and sets \p error.
6317 mono_value_box_checked (MonoDomain *domain, MonoClass *klass, gpointer value, MonoError *error)
6319 MONO_REQ_GC_UNSAFE_MODE;
6326 g_assert (klass->valuetype);
6327 if (mono_class_is_nullable (klass))
6328 return mono_nullable_box ((guint8 *)value, klass, error);
6330 vtable = mono_class_vtable (domain, klass);
6333 size = mono_class_instance_size (klass);
6334 res = mono_object_new_alloc_specific_checked (vtable, error);
6335 return_val_if_nok (error, NULL);
6337 size = size - sizeof (MonoObject);
6339 if (mono_gc_is_moving ()) {
6340 g_assert (size == mono_class_value_size (klass, NULL));
6341 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
6343 #if NO_UNALIGNED_ACCESS
6344 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6348 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
6351 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
6354 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
6357 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
6360 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6364 if (klass->has_finalize) {
6365 mono_object_register_finalizer (res);
6366 return_val_if_nok (error, NULL);
6373 * \param dest destination pointer
6374 * \param src source pointer
6375 * \param klass a valuetype class
6376 * Copy a valuetype from \p src to \p dest. This function must be used
6377 * when \p klass contains reference fields.
6380 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
6382 MONO_REQ_GC_UNSAFE_MODE;
6384 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
6388 * mono_value_copy_array:
6389 * \param dest destination array
6390 * \param dest_idx index in the \p dest array
6391 * \param src source pointer
6392 * \param count number of items
6393 * Copy \p count valuetype items from \p src to the array \p dest at index \p dest_idx.
6394 * This function must be used when \p klass contains references fields.
6395 * Overlap is handled.
6398 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
6400 MONO_REQ_GC_UNSAFE_MODE;
6402 int size = mono_array_element_size (dest->obj.vtable->klass);
6403 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
6404 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
6405 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
6409 * mono_object_get_domain:
6410 * \param obj object to query
6411 * \returns the \c MonoDomain where the object is hosted
6414 mono_object_get_domain (MonoObject *obj)
6416 MONO_REQ_GC_UNSAFE_MODE;
6418 return mono_object_domain (obj);
6422 * mono_object_get_class:
6423 * \param obj object to query
6424 * Use this function to obtain the \c MonoClass* for a given \c MonoObject.
6425 * \returns the \c MonoClass of the object.
6428 mono_object_get_class (MonoObject *obj)
6430 MONO_REQ_GC_UNSAFE_MODE;
6432 return mono_object_class (obj);
6435 * mono_object_get_size:
6436 * \param o object to query
6437 * \returns the size, in bytes, of \p o
6440 mono_object_get_size (MonoObject* o)
6442 MONO_REQ_GC_UNSAFE_MODE;
6444 MonoClass* klass = mono_object_class (o);
6445 if (klass == mono_defaults.string_class) {
6446 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
6447 } else if (o->vtable->rank) {
6448 MonoArray *array = (MonoArray*)o;
6449 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
6450 if (array->bounds) {
6453 size += sizeof (MonoArrayBounds) * o->vtable->rank;
6457 return mono_class_instance_size (klass);
6462 * mono_object_unbox:
6463 * \param obj object to unbox
6464 * \returns a pointer to the start of the valuetype boxed in this
6467 * This method will assert if the object passed is not a valuetype.
6470 mono_object_unbox (MonoObject *obj)
6472 MONO_REQ_GC_UNSAFE_MODE;
6474 /* add assert for valuetypes? */
6475 g_assert (obj->vtable->klass->valuetype);
6476 return ((char*)obj) + sizeof (MonoObject);
6480 * mono_object_isinst:
6481 * \param obj an object
6482 * \param klass a pointer to a class
6483 * \returns \p obj if \p obj is derived from \p klass or NULL otherwise.
6486 mono_object_isinst (MonoObject *obj_raw, MonoClass *klass)
6488 MONO_REQ_GC_UNSAFE_MODE;
6490 HANDLE_FUNCTION_ENTER ();
6491 MONO_HANDLE_DCL (MonoObject, obj);
6493 MonoObjectHandle result = mono_object_handle_isinst (obj, klass, &error);
6494 mono_error_cleanup (&error);
6495 HANDLE_FUNCTION_RETURN_OBJ (result);
6500 * mono_object_isinst_checked:
6501 * \param obj an object
6502 * \param klass a pointer to a class
6503 * \param error set on error
6504 * \returns \p obj if \p obj is derived from \p klass or NULL if it isn't.
6505 * On failure returns NULL and sets \p error.
6508 mono_object_isinst_checked (MonoObject *obj_raw, MonoClass *klass, MonoError *error)
6510 MONO_REQ_GC_UNSAFE_MODE;
6512 HANDLE_FUNCTION_ENTER ();
6514 MONO_HANDLE_DCL (MonoObject, obj);
6515 MonoObjectHandle result = mono_object_handle_isinst (obj, klass, error);
6516 HANDLE_FUNCTION_RETURN_OBJ (result);
6520 * mono_object_handle_isinst:
6521 * \param obj an object
6522 * \param klass a pointer to a class
6523 * \param error set on error
6524 * \returns \p obj if \p obj is derived from \p klass or NULL if it isn't.
6525 * On failure returns NULL and sets \p error.
6528 mono_object_handle_isinst (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
6533 mono_class_init (klass);
6535 if (mono_class_is_marshalbyref (klass) || mono_class_is_interface (klass)) {
6536 return mono_object_handle_isinst_mbyref (obj, klass, error);
6539 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6541 if (!MONO_HANDLE_IS_NULL (obj) && mono_class_is_assignable_from (klass, mono_handle_class (obj)))
6542 MONO_HANDLE_ASSIGN (result, obj);
6547 * mono_object_isinst_mbyref:
6550 mono_object_isinst_mbyref (MonoObject *obj_raw, MonoClass *klass)
6552 MONO_REQ_GC_UNSAFE_MODE;
6554 HANDLE_FUNCTION_ENTER ();
6556 MONO_HANDLE_DCL (MonoObject, obj);
6557 MonoObjectHandle result = mono_object_handle_isinst_mbyref (obj, klass, &error);
6558 mono_error_cleanup (&error); /* FIXME better API that doesn't swallow the error */
6559 HANDLE_FUNCTION_RETURN_OBJ (result);
6563 mono_object_handle_isinst_mbyref (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
6567 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6569 if (MONO_HANDLE_IS_NULL (obj))
6572 MonoVTable *vt = MONO_HANDLE_GETVAL (obj, vtable);
6574 if (mono_class_is_interface (klass)) {
6575 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
6576 MONO_HANDLE_ASSIGN (result, obj);
6580 /* casting an array one of the invariant interfaces that must act as such */
6581 if (klass->is_array_special_interface) {
6582 if (mono_class_is_assignable_from (klass, vt->klass)) {
6583 MONO_HANDLE_ASSIGN (result, obj);
6588 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
6589 else if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, mono_handle_class (obj))) {
6590 MONO_HANDLE_ASSIGN (result, obj);
6594 MonoClass *oklass = vt->klass;
6595 if (mono_class_is_transparent_proxy (oklass)){
6596 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), remote_class);
6597 oklass = remote_class->proxy_class;
6600 mono_class_setup_supertypes (klass);
6601 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass)) {
6602 MONO_HANDLE_ASSIGN (result, obj);
6606 #ifndef DISABLE_REMOTING
6607 if (mono_class_is_transparent_proxy (vt->klass))
6609 MonoBoolean custom_type_info = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), custom_type_info);
6610 if (!custom_type_info)
6612 MonoDomain *domain = mono_domain_get ();
6613 MonoObjectHandle rp = MONO_HANDLE_NEW (MonoObject, NULL);
6614 MONO_HANDLE_GET (rp, MONO_HANDLE_CAST (MonoTransparentProxy, obj), rp);
6615 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
6616 MonoMethod *im = NULL;
6619 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
6621 mono_error_set_not_supported (error, "Linked away.");
6624 im = mono_object_handle_get_virtual_method (rp, im, error);
6629 MonoReflectionTypeHandle reftype = mono_type_get_object_handle (domain, &klass->byval_arg, error);
6633 pa [0] = MONO_HANDLE_RAW (reftype);
6634 pa [1] = MONO_HANDLE_RAW (obj);
6635 MonoObject *res = mono_runtime_invoke_checked (im, MONO_HANDLE_RAW (rp), pa, error);
6639 if (*(MonoBoolean *) mono_object_unbox(res)) {
6640 /* Update the vtable of the remote type, so it can safely cast to this new type */
6641 mono_upgrade_remote_class (domain, obj, klass, error);
6644 MONO_HANDLE_ASSIGN (result, obj);
6647 #endif /* DISABLE_REMOTING */
6653 * mono_object_castclass_mbyref:
6654 * \param obj an object
6655 * \param klass a pointer to a class
6656 * \returns \p obj if \p obj is derived from \p klass, returns NULL otherwise.
6659 mono_object_castclass_mbyref (MonoObject *obj_raw, MonoClass *klass)
6661 MONO_REQ_GC_UNSAFE_MODE;
6662 HANDLE_FUNCTION_ENTER ();
6664 MONO_HANDLE_DCL (MonoObject, obj);
6665 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6666 if (MONO_HANDLE_IS_NULL (obj))
6668 MONO_HANDLE_ASSIGN (result, mono_object_handle_isinst_mbyref (obj, klass, &error));
6669 mono_error_cleanup (&error);
6671 HANDLE_FUNCTION_RETURN_OBJ (result);
6675 MonoDomain *orig_domain;
6681 str_lookup (MonoDomain *domain, gpointer user_data)
6683 MONO_REQ_GC_UNSAFE_MODE;
6685 LDStrInfo *info = (LDStrInfo *)user_data;
6686 if (info->res || domain == info->orig_domain)
6688 info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
6692 mono_string_get_pinned (MonoString *str, MonoError *error)
6694 MONO_REQ_GC_UNSAFE_MODE;
6698 /* We only need to make a pinned version of a string if this is a moving GC */
6699 if (!mono_gc_is_moving ())
6703 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
6704 news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
6706 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
6707 news->length = mono_string_length (str);
6709 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6715 mono_string_is_interned_lookup (MonoString *str, int insert, MonoError *error)
6717 MONO_REQ_GC_UNSAFE_MODE;
6719 MonoGHashTable *ldstr_table;
6720 MonoString *s, *res;
6725 domain = ((MonoObject *)str)->vtable->domain;
6726 ldstr_table = domain->ldstr_table;
6728 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6734 /* Allocate outside the lock */
6736 s = mono_string_get_pinned (str, error);
6737 return_val_if_nok (error, NULL);
6740 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6745 mono_g_hash_table_insert (ldstr_table, s, s);
6750 LDStrInfo ldstr_info;
6751 ldstr_info.orig_domain = domain;
6752 ldstr_info.ins = str;
6753 ldstr_info.res = NULL;
6755 mono_domain_foreach (str_lookup, &ldstr_info);
6756 if (ldstr_info.res) {
6758 * the string was already interned in some other domain:
6759 * intern it in the current one as well.
6761 mono_g_hash_table_insert (ldstr_table, str, str);
6771 * mono_string_is_interned:
6772 * \param o String to probe
6773 * \returns Whether the string has been interned.
6776 mono_string_is_interned (MonoString *o)
6779 MonoString *result = mono_string_is_interned_lookup (o, FALSE, &error);
6780 /* This function does not fail. */
6781 mono_error_assert_ok (&error);
6786 * mono_string_intern:
6787 * \param o String to intern
6788 * Interns the string passed.
6789 * \returns The interned string.
6792 mono_string_intern (MonoString *str)
6795 MonoString *result = mono_string_intern_checked (str, &error);
6796 mono_error_assert_ok (&error);
6801 * mono_string_intern_checked:
6802 * \param o String to intern
6803 * \param error set on error.
6804 * Interns the string passed.
6805 * \returns The interned string. On failure returns NULL and sets \p error
6808 mono_string_intern_checked (MonoString *str, MonoError *error)
6810 MONO_REQ_GC_UNSAFE_MODE;
6814 return mono_string_is_interned_lookup (str, TRUE, error);
6819 * \param domain the domain where the string will be used.
6820 * \param image a metadata context
6821 * \param idx index into the user string table.
6822 * Implementation for the \c ldstr opcode.
6823 * \returns a loaded string from the \p image / \p idx combination.
6826 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
6829 MonoString *result = mono_ldstr_checked (domain, image, idx, &error);
6830 mono_error_cleanup (&error);
6835 * mono_ldstr_checked:
6836 * \param domain the domain where the string will be used.
6837 * \param image a metadata context
6838 * \param idx index into the user string table.
6839 * \param error set on error.
6840 * Implementation for the \c ldstr opcode.
6841 * \returns A loaded string from the \p image / \p idx combination.
6842 * On failure returns NULL and sets \p error.
6845 mono_ldstr_checked (MonoDomain *domain, MonoImage *image, guint32 idx, MonoError *error)
6847 MONO_REQ_GC_UNSAFE_MODE;
6850 if (image->dynamic) {
6851 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL, error);
6854 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6855 return NULL; /*FIXME we should probably be raising an exception here*/
6856 MonoString *str = mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx), error);
6862 * mono_ldstr_metadata_sig
6863 * \param domain the domain for the string
6864 * \param sig the signature of a metadata string
6865 * \param error set on error
6866 * \returns a \c MonoString for a string stored in the metadata. On
6867 * failure returns NULL and sets \p error.
6870 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error)
6872 MONO_REQ_GC_UNSAFE_MODE;
6875 const char *str = sig;
6876 MonoString *o, *interned;
6879 len2 = mono_metadata_decode_blob_size (str, &str);
6882 o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, error);
6883 return_val_if_nok (error, NULL);
6884 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
6887 guint16 *p2 = (guint16*)mono_string_chars (o);
6888 for (i = 0; i < len2; ++i) {
6889 *p2 = GUINT16_FROM_LE (*p2);
6895 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6898 return interned; /* o will get garbage collected */
6900 o = mono_string_get_pinned (o, error);
6903 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6905 mono_g_hash_table_insert (domain->ldstr_table, o, o);
6917 * Same as mono_ldstr, but return a NULL terminated utf8 string instead
6921 mono_ldstr_utf8 (MonoImage *image, guint32 idx, MonoError *error)
6927 GError *gerror = NULL;
6931 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6932 return NULL; /*FIXME we should probably be raising an exception here*/
6933 str = mono_metadata_user_string (image, idx);
6935 len2 = mono_metadata_decode_blob_size (str, &str);
6938 as = g_utf16_to_utf8 ((guint16*)str, len2, NULL, &written, &gerror);
6940 mono_error_set_argument (error, "string", "%s", gerror->message);
6941 g_error_free (gerror);
6944 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6945 if (len2 > written) {
6946 /* allocate the total length and copy the part of the string that has been converted */
6947 char *as2 = (char *)g_malloc0 (len2);
6948 memcpy (as2, as, written);
6957 * mono_string_to_utf8:
6958 * \param s a \c System.String
6959 * \deprecated Use \c mono_string_to_utf8_checked to avoid having an exception arbitrarily raised.
6960 * \returns the UTF-8 representation for \p s.
6961 * The resulting buffer needs to be freed with \c mono_free().
6964 mono_string_to_utf8 (MonoString *s)
6966 MONO_REQ_GC_UNSAFE_MODE;
6969 char *result = mono_string_to_utf8_checked (s, &error);
6971 if (!is_ok (&error)) {
6972 mono_error_cleanup (&error);
6979 * mono_string_to_utf8_checked:
6980 * \param s a \c System.String
6981 * \param error a \c MonoError.
6982 * Converts a \c MonoString to its UTF-8 representation. May fail; check
6983 * \p error to determine whether the conversion was successful.
6984 * The resulting buffer should be freed with \c mono_free().
6987 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
6989 MONO_REQ_GC_UNSAFE_MODE;
6993 GError *gerror = NULL;
7001 return g_strdup ("");
7003 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
7005 mono_error_set_argument (error, "string", "%s", gerror->message);
7006 g_error_free (gerror);
7009 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
7010 if (s->length > written) {
7011 /* allocate the total length and copy the part of the string that has been converted */
7012 char *as2 = (char *)g_malloc0 (s->length);
7013 memcpy (as2, as, written);
7022 mono_string_handle_to_utf8 (MonoStringHandle s, MonoError *error)
7024 return mono_string_to_utf8_checked (MONO_HANDLE_RAW (s), error);
7028 * mono_string_to_utf8_ignore:
7029 * \param s a MonoString
7030 * Converts a \c MonoString to its UTF-8 representation. Will ignore
7031 * invalid surrogate pairs.
7032 * The resulting buffer should be freed with \c mono_free().
7035 mono_string_to_utf8_ignore (MonoString *s)
7037 MONO_REQ_GC_UNSAFE_MODE;
7046 return g_strdup ("");
7048 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
7050 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
7051 if (s->length > written) {
7052 /* allocate the total length and copy the part of the string that has been converted */
7053 char *as2 = (char *)g_malloc0 (s->length);
7054 memcpy (as2, as, written);
7063 * mono_string_to_utf8_image_ignore:
7064 * \param s a \c System.String
7065 * Same as \c mono_string_to_utf8_ignore, but allocate the string from the image mempool.
7068 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
7070 MONO_REQ_GC_UNSAFE_MODE;
7072 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
7076 * mono_string_to_utf8_mp_ignore:
7077 * \param s a \c System.String
7078 * Same as \c mono_string_to_utf8_ignore, but allocate the string from a mempool.
7081 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
7083 MONO_REQ_GC_UNSAFE_MODE;
7085 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
7090 * mono_string_to_utf16:
7091 * \param s a \c MonoString
7092 * \returns a null-terminated array of the UTF-16 chars
7093 * contained in \p s. The result must be freed with \c g_free().
7094 * This is a temporary helper until our string implementation
7095 * is reworked to always include the null-terminating char.
7098 mono_string_to_utf16 (MonoString *s)
7100 MONO_REQ_GC_UNSAFE_MODE;
7107 as = (char *)g_malloc ((s->length * 2) + 2);
7108 as [(s->length * 2)] = '\0';
7109 as [(s->length * 2) + 1] = '\0';
7112 return (gunichar2 *)(as);
7115 memcpy (as, mono_string_chars(s), s->length * 2);
7116 return (gunichar2 *)(as);
7120 * mono_string_to_utf32:
7121 * \param s a \c MonoString
7122 * \returns a null-terminated array of the UTF-32 (UCS-4) chars
7123 * contained in \p s. The result must be freed with \c g_free().
7126 mono_string_to_utf32 (MonoString *s)
7128 MONO_REQ_GC_UNSAFE_MODE;
7130 mono_unichar4 *utf32_output = NULL;
7131 GError *error = NULL;
7132 glong items_written;
7137 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
7140 g_error_free (error);
7142 return utf32_output;
7146 * mono_string_from_utf16:
7147 * \param data the UTF-16 string (LPWSTR) to convert
7148 * Converts a NULL-terminated UTF-16 string (LPWSTR) to a \c MonoString.
7149 * \returns a \c MonoString.
7152 mono_string_from_utf16 (gunichar2 *data)
7155 MonoString *result = mono_string_from_utf16_checked (data, &error);
7156 mono_error_cleanup (&error);
7161 * mono_string_from_utf16_checked:
7162 * \param data the UTF-16 string (LPWSTR) to convert
7163 * \param error set on error
7164 * Converts a NULL-terminated UTF-16 string (LPWSTR) to a \c MonoString.
7165 * \returns a \c MonoString. On failure sets \p error and returns NULL.
7168 mono_string_from_utf16_checked (gunichar2 *data, MonoError *error)
7171 MONO_REQ_GC_UNSAFE_MODE;
7174 MonoDomain *domain = mono_domain_get ();
7180 while (data [len]) len++;
7182 return mono_string_new_utf16_checked (domain, data, len, error);
7186 * mono_string_from_utf32:
7187 * \param data the UTF-32 string (LPWSTR) to convert
7188 * Converts a UTF-32 (UCS-4) string to a \c MonoString.
7189 * \returns a \c MonoString.
7192 mono_string_from_utf32 (mono_unichar4 *data)
7195 MonoString *result = mono_string_from_utf32_checked (data, &error);
7196 mono_error_cleanup (&error);
7201 * mono_string_from_utf32_checked:
7202 * \param data the UTF-32 string (LPWSTR) to convert
7203 * \param error set on error
7204 * Converts a UTF-32 (UCS-4) string to a \c MonoString.
7205 * \returns a \c MonoString. On failure returns NULL and sets \p error.
7208 mono_string_from_utf32_checked (mono_unichar4 *data, MonoError *error)
7210 MONO_REQ_GC_UNSAFE_MODE;
7213 MonoString* result = NULL;
7214 mono_unichar2 *utf16_output = NULL;
7215 GError *gerror = NULL;
7216 glong items_written;
7222 while (data [len]) len++;
7224 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &gerror);
7227 g_error_free (gerror);
7229 result = mono_string_from_utf16_checked (utf16_output, error);
7230 g_free (utf16_output);
7235 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
7237 MONO_REQ_GC_UNSAFE_MODE;
7244 r = mono_string_to_utf8_ignore (s);
7246 r = mono_string_to_utf8_checked (s, error);
7247 if (!mono_error_ok (error))
7254 len = strlen (r) + 1;
7256 mp_s = (char *)mono_mempool_alloc (mp, len);
7258 mp_s = (char *)mono_image_alloc (image, len);
7260 memcpy (mp_s, r, len);
7268 * mono_string_to_utf8_image:
7269 * \param s a \c System.String
7270 * Same as \c mono_string_to_utf8, but allocate the string from the image mempool.
7273 mono_string_to_utf8_image (MonoImage *image, MonoStringHandle s, MonoError *error)
7275 MONO_REQ_GC_UNSAFE_MODE;
7277 return mono_string_to_utf8_internal (NULL, image, MONO_HANDLE_RAW (s), FALSE, error); /* FIXME pin the string */
7281 * mono_string_to_utf8_mp:
7282 * \param s a \c System.String
7283 * Same as \c mono_string_to_utf8, but allocate the string from a mempool.
7286 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
7288 MONO_REQ_GC_UNSAFE_MODE;
7290 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
7294 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
7297 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
7299 eh_callbacks = *cbs;
7302 MonoRuntimeExceptionHandlingCallbacks *
7303 mono_get_eh_callbacks (void)
7305 return &eh_callbacks;
7309 * mono_raise_exception:
7310 * \param ex exception object
7311 * Signal the runtime that the exception \p ex has been raised in unmanaged code.
7314 mono_raise_exception (MonoException *ex)
7316 MONO_REQ_GC_UNSAFE_MODE;
7319 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
7320 * that will cause gcc to omit the function epilog, causing problems when
7321 * the JIT tries to walk the stack, since the return address on the stack
7322 * will point into the next function in the executable, not this one.
7324 eh_callbacks.mono_raise_exception (ex);
7328 * mono_raise_exception:
7329 * \param ex exception object
7330 * Signal the runtime that the exception \p ex has been raised in unmanaged code.
7333 mono_reraise_exception (MonoException *ex)
7335 MONO_REQ_GC_UNSAFE_MODE;
7338 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
7339 * that will cause gcc to omit the function epilog, causing problems when
7340 * the JIT tries to walk the stack, since the return address on the stack
7341 * will point into the next function in the executable, not this one.
7343 eh_callbacks.mono_reraise_exception (ex);
7347 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
7349 MONO_REQ_GC_UNSAFE_MODE;
7351 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
7355 * mono_wait_handle_new:
7356 * \param domain Domain where the object will be created
7357 * \param handle Handle for the wait handle
7358 * \param error set on error.
7359 * \returns A new \c MonoWaitHandle created in the given domain for the
7360 * given handle. On failure returns NULL and sets \p error.
7363 mono_wait_handle_new (MonoDomain *domain, HANDLE handle, MonoError *error)
7365 MONO_REQ_GC_UNSAFE_MODE;
7367 MonoWaitHandle *res;
7368 gpointer params [1];
7369 static MonoMethod *handle_set;
7372 res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, error);
7373 return_val_if_nok (error, NULL);
7375 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
7377 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
7379 params [0] = &handle;
7381 mono_runtime_invoke_checked (handle_set, res, params, error);
7386 mono_wait_handle_get_handle (MonoWaitHandle *handle)
7388 MONO_REQ_GC_UNSAFE_MODE;
7390 static MonoClassField *f_safe_handle = NULL;
7393 if (!f_safe_handle) {
7394 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safeWaitHandle");
7395 g_assert (f_safe_handle);
7398 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
7404 mono_runtime_capture_context (MonoDomain *domain, MonoError *error)
7406 MONO_REQ_GC_UNSAFE_MODE;
7408 RuntimeInvokeFunction runtime_invoke;
7412 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
7413 MonoMethod *method = mono_get_context_capture_method ();
7414 MonoMethod *wrapper;
7417 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
7418 domain->capture_context_runtime_invoke = mono_compile_method_checked (wrapper, error);
7419 return_val_if_nok (error, NULL);
7420 domain->capture_context_method = mono_compile_method_checked (method, error);
7421 return_val_if_nok (error, NULL);
7424 runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
7426 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
7429 * mono_async_result_new:
7430 * \param domain domain where the object will be created.
7431 * \param handle wait handle.
7432 * \param state state to pass to AsyncResult
7433 * \param data C closure data.
7434 * \param error set on error.
7435 * Creates a new MonoAsyncResult (\c AsyncResult C# class) in the given domain.
7436 * If the handle is not null, the handle is initialized to a \c MonoWaitHandle.
7437 * On failure returns NULL and sets \p error.
7440 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data, MonoError *error)
7442 MONO_REQ_GC_UNSAFE_MODE;
7445 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, error);
7446 return_val_if_nok (error, NULL);
7447 MonoObject *context = mono_runtime_capture_context (domain, error);
7448 return_val_if_nok (error, NULL);
7449 /* we must capture the execution context from the original thread */
7451 MONO_OBJECT_SETREF (res, execution_context, context);
7452 /* note: result may be null if the flow is suppressed */
7455 res->data = (void **)data;
7456 MONO_OBJECT_SETREF (res, object_data, object_data);
7457 MONO_OBJECT_SETREF (res, async_state, state);
7458 MonoWaitHandle *wait_handle = mono_wait_handle_new (domain, handle, error);
7459 return_val_if_nok (error, NULL);
7461 MONO_OBJECT_SETREF (res, handle, (MonoObject *) wait_handle);
7463 res->sync_completed = FALSE;
7464 res->completed = FALSE;
7470 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
7472 MONO_REQ_GC_UNSAFE_MODE;
7479 g_assert (ares->async_delegate);
7481 ac = (MonoAsyncCall*) ares->object_data;
7483 res = mono_runtime_delegate_invoke_checked (ares->async_delegate, (void**) &ares->async_state, &error);
7484 if (mono_error_set_pending_exception (&error))
7487 gpointer wait_event = NULL;
7489 ac->msg->exc = NULL;
7491 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args, &error);
7493 /* The exit side of the invoke must not be aborted as it would leave the runtime in an undefined state */
7494 mono_threads_begin_abort_protected_block ();
7496 if (!ac->msg->exc) {
7497 MonoException *ex = mono_error_convert_to_exception (&error);
7498 ac->msg->exc = (MonoObject *)ex;
7500 mono_error_cleanup (&error);
7503 MONO_OBJECT_SETREF (ac, res, res);
7505 mono_monitor_enter ((MonoObject*) ares);
7506 ares->completed = 1;
7508 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
7509 mono_monitor_exit ((MonoObject*) ares);
7511 if (wait_event != NULL)
7512 mono_w32event_set (wait_event);
7514 error_init (&error); //the else branch would leave it in an undefined state
7516 mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
7518 mono_threads_end_abort_protected_block ();
7520 if (mono_error_set_pending_exception (&error))
7528 mono_message_init (MonoDomain *domain,
7529 MonoMethodMessage *this_obj,
7530 MonoReflectionMethod *method,
7531 MonoArray *out_args,
7534 MONO_REQ_GC_UNSAFE_MODE;
7536 static MonoMethod *init_message_method = NULL;
7538 if (!init_message_method) {
7539 init_message_method = mono_class_get_method_from_name (mono_defaults.mono_method_message_class, "InitMessage", 2);
7540 g_assert (init_message_method != NULL);
7544 /* FIXME set domain instead? */
7545 g_assert (domain == mono_domain_get ());
7552 mono_runtime_invoke_checked (init_message_method, this_obj, args, error);
7553 return is_ok (error);
7556 #ifndef DISABLE_REMOTING
7558 * mono_remoting_invoke:
7559 * \param real_proxy pointer to a \c RealProxy object
7560 * \param msg The \c MonoMethodMessage to execute
7561 * \param exc used to store exceptions
7562 * \param out_args used to store output arguments
7563 * This is used to call \c RealProxy::Invoke(). \c RealProxy::Invoke() returns an
7564 * \c IMessage interface and it is not trivial to extract results from there. So
7565 * we call an helper method \c PrivateInvoke instead of calling
7566 * \c RealProxy::Invoke() directly.
7567 * \returns the result object.
7570 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, MonoObject **exc, MonoArray **out_args, MonoError *error)
7572 MONO_REQ_GC_UNSAFE_MODE;
7575 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
7582 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
7585 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
7587 mono_error_set_not_supported (error, "Linked away.");
7590 real_proxy->vtable->domain->private_invoke_method = im;
7593 pa [0] = real_proxy;
7598 o = mono_runtime_try_invoke (im, NULL, pa, exc, error);
7599 return_val_if_nok (error, NULL);
7606 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
7607 MonoObject **exc, MonoArray **out_args, MonoError *error)
7609 MONO_REQ_GC_UNSAFE_MODE;
7611 static MonoClass *object_array_klass;
7616 MonoMethodSignature *sig;
7618 int i, j, outarg_count = 0;
7620 #ifndef DISABLE_REMOTING
7621 if (target && mono_object_is_transparent_proxy (target)) {
7622 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
7623 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7624 target = tp->rp->unwrapped_server;
7626 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args, error);
7631 domain = mono_domain_get ();
7632 method = msg->method->method;
7633 sig = mono_method_signature (method);
7635 for (i = 0; i < sig->param_count; i++) {
7636 if (sig->params [i]->byref)
7640 if (!object_array_klass) {
7643 klass = mono_array_class_get (mono_defaults.object_class, 1);
7646 mono_memory_barrier ();
7647 object_array_klass = klass;
7650 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, error);
7651 return_val_if_nok (error, NULL);
7653 mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
7656 MonoObject *ret = mono_runtime_try_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc, error);
7657 return_val_if_nok (error, NULL);
7659 for (i = 0, j = 0; i < sig->param_count; i++) {
7660 if (sig->params [i]->byref) {
7662 arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
7663 mono_array_setref (*out_args, j, arg);
7672 * prepare_to_string_method:
7674 * @target: Set to @obj or unboxed value if a valuetype
7676 * Returns: the ToString override for @obj. If @obj is a valuetype, @target is unboxed otherwise it's @obj.
7679 prepare_to_string_method (MonoObject *obj, void **target)
7681 MONO_REQ_GC_UNSAFE_MODE;
7683 static MonoMethod *to_string = NULL;
7691 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
7693 method = mono_object_get_virtual_method (obj, to_string);
7695 // Unbox value type if needed
7696 if (mono_class_is_valuetype (mono_method_get_class (method))) {
7697 *target = mono_object_unbox (obj);
7703 * mono_object_to_string:
7704 * \param obj The object
7705 * \param exc Any exception thrown by \c ToString. May be NULL.
7706 * \returns the result of calling \c ToString on an object.
7709 mono_object_to_string (MonoObject *obj, MonoObject **exc)
7712 MonoString *s = NULL;
7714 MonoMethod *method = prepare_to_string_method (obj, &target);
7716 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
7717 if (*exc == NULL && !mono_error_ok (&error))
7718 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
7720 mono_error_cleanup (&error);
7722 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
7723 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
7730 * mono_object_to_string_checked:
7731 * \param obj The object
7732 * \param error Set on error.
7733 * \returns the result of calling \c ToString() on an object. If the
7734 * method cannot be invoked or if it raises an exception, sets \p error
7738 mono_object_to_string_checked (MonoObject *obj, MonoError *error)
7742 MonoMethod *method = prepare_to_string_method (obj, &target);
7743 return (MonoString*) mono_runtime_invoke_checked (method, target, NULL, error);
7747 * mono_object_try_to_string:
7748 * \param obj The object
7749 * \param exc Any exception thrown by \c ToString(). Must not be NULL.
7750 * \param error Set if method cannot be invoked.
7751 * \returns the result of calling \c ToString() on an object. If the
7752 * method cannot be invoked sets \p error, if it raises an exception sets \p exc,
7756 mono_object_try_to_string (MonoObject *obj, MonoObject **exc, MonoError *error)
7761 MonoMethod *method = prepare_to_string_method (obj, &target);
7762 return (MonoString*) mono_runtime_try_invoke (method, target, NULL, exc, error);
7768 get_native_backtrace (MonoException *exc_raw)
7770 HANDLE_FUNCTION_ENTER ();
7771 MONO_HANDLE_DCL(MonoException, exc);
7772 char * trace = mono_exception_handle_get_native_backtrace (exc);
7773 HANDLE_FUNCTION_RETURN_VAL (trace);
7777 * mono_print_unhandled_exception:
7778 * \param exc The exception
7779 * Prints the unhandled exception.
7782 mono_print_unhandled_exception (MonoObject *exc)
7784 MONO_REQ_GC_UNSAFE_MODE;
7787 char *message = (char*)"";
7788 gboolean free_message = FALSE;
7791 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
7792 message = g_strdup ("OutOfMemoryException");
7793 free_message = TRUE;
7794 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
7795 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
7796 free_message = TRUE;
7799 if (((MonoException*)exc)->native_trace_ips) {
7800 message = get_native_backtrace ((MonoException*)exc);
7801 free_message = TRUE;
7803 MonoObject *other_exc = NULL;
7804 str = mono_object_try_to_string (exc, &other_exc, &error);
7805 if (other_exc == NULL && !is_ok (&error))
7806 other_exc = (MonoObject*)mono_error_convert_to_exception (&error);
7808 mono_error_cleanup (&error);
7810 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
7811 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
7813 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
7814 original_backtrace, nested_backtrace);
7816 g_free (original_backtrace);
7817 g_free (nested_backtrace);
7818 free_message = TRUE;
7820 message = mono_string_to_utf8_checked (str, &error);
7821 if (!mono_error_ok (&error)) {
7822 mono_error_cleanup (&error);
7823 message = (char *) "";
7825 free_message = TRUE;
7832 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
7833 * exc->vtable->klass->name, message);
7835 g_printerr ("\nUnhandled Exception:\n%s\n", message);
7842 * mono_delegate_ctor_with_method:
7843 * \param this pointer to an uninitialized delegate object
7844 * \param target target object
7845 * \param addr pointer to native code
7846 * \param method method
7847 * \param error set on error.
7848 * Initialize a delegate and sets a specific method, not the one
7849 * associated with \p addr. This is useful when sharing generic code.
7850 * In that case \p addr will most probably not be associated with the
7851 * correct instantiation of the method.
7852 * On failure returns FALSE and sets \p error.
7855 mono_delegate_ctor_with_method (MonoObjectHandle this_obj, MonoObjectHandle target, gpointer addr, MonoMethod *method, MonoError *error)
7857 MONO_REQ_GC_UNSAFE_MODE;
7860 MonoDelegateHandle delegate = MONO_HANDLE_CAST (MonoDelegate, this_obj);
7862 g_assert (!MONO_HANDLE_IS_NULL (this_obj));
7865 MonoClass *klass = mono_handle_class (this_obj);
7866 g_assert (mono_class_has_parent (klass, mono_defaults.multicastdelegate_class));
7869 MONO_HANDLE_SETVAL (delegate, method, MonoMethod*, method);
7871 UnlockedIncrement (&mono_stats.delegate_creations);
7873 #ifndef DISABLE_REMOTING
7874 if (!MONO_HANDLE_IS_NULL (target) && mono_class_is_transparent_proxy (mono_handle_class (target))) {
7876 method = mono_marshal_get_remoting_invoke (method);
7877 #ifdef ENABLE_INTERPRETER
7878 //g_error ("need RuntimeMethod in method_ptr when using interpreter");
7880 MONO_HANDLE_SETVAL (delegate, method_ptr, gpointer, mono_compile_method_checked (method, error));
7881 return_val_if_nok (error, FALSE);
7882 MONO_HANDLE_SET (delegate, target, target);
7886 MONO_HANDLE_SETVAL (delegate, method_ptr, gpointer, addr);
7887 MONO_HANDLE_SET (delegate, target, target);
7890 MONO_HANDLE_SETVAL (delegate, invoke_impl, gpointer, callbacks.create_delegate_trampoline (MONO_HANDLE_DOMAIN (delegate), mono_handle_class (delegate)));
7891 if (callbacks.init_delegate)
7892 callbacks.init_delegate (MONO_HANDLE_RAW (delegate)); /* FIXME: update init_delegate callback to take a MonoDelegateHandle */
7897 * mono_delegate_ctor:
7898 * \param this pointer to an uninitialized delegate object
7899 * \param target target object
7900 * \param addr pointer to native code
7901 * \param error set on error.
7902 * This is used to initialize a delegate.
7903 * On failure returns FALSE and sets \p error.
7906 mono_delegate_ctor (MonoObjectHandle this_obj, MonoObjectHandle target, gpointer addr, MonoError *error)
7908 MONO_REQ_GC_UNSAFE_MODE;
7911 MonoDomain *domain = mono_domain_get ();
7913 MonoMethod *method = NULL;
7917 ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
7919 if (!ji && domain != mono_get_root_domain ())
7920 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
7922 method = mono_jit_info_get_method (ji);
7923 g_assert (!mono_class_is_gtd (method->klass));
7926 return mono_delegate_ctor_with_method (this_obj, target, addr, method, error);
7930 * mono_method_call_message_new:
7931 * \param method method to encapsulate
7932 * \param params parameters to the method
7933 * \param invoke optional, delegate invoke.
7934 * \param cb async callback delegate.
7935 * \param state state passed to the async callback.
7936 * \param error set on error.
7937 * Translates arguments pointers into a \c MonoMethodMessage.
7938 * On failure returns NULL and sets \p error.
7941 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
7942 MonoDelegate **cb, MonoObject **state, MonoError *error)
7944 MONO_REQ_GC_UNSAFE_MODE;
7948 MonoDomain *domain = mono_domain_get ();
7949 MonoMethodSignature *sig = mono_method_signature (method);
7950 MonoMethodMessage *msg;
7953 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
7954 return_val_if_nok (error, NULL);
7957 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, error);
7958 return_val_if_nok (error, NULL);
7959 mono_message_init (domain, msg, rm, NULL, error);
7960 return_val_if_nok (error, NULL);
7961 count = sig->param_count - 2;
7963 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
7964 return_val_if_nok (error, NULL);
7965 mono_message_init (domain, msg, rm, NULL, error);
7966 return_val_if_nok (error, NULL);
7967 count = sig->param_count;
7970 for (i = 0; i < count; i++) {
7975 if (sig->params [i]->byref)
7976 vpos = *((gpointer *)params [i]);
7980 klass = mono_class_from_mono_type (sig->params [i]);
7982 if (klass->valuetype) {
7983 arg = mono_value_box_checked (domain, klass, vpos, error);
7984 return_val_if_nok (error, NULL);
7986 arg = *((MonoObject **)vpos);
7988 mono_array_setref (msg->args, i, arg);
7991 if (cb != NULL && state != NULL) {
7992 *cb = *((MonoDelegate **)params [i]);
7994 *state = *((MonoObject **)params [i]);
8001 * mono_method_return_message_restore:
8003 * Restore results from message based processing back to arguments pointers
8006 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args, MonoError *error)
8008 MONO_REQ_GC_UNSAFE_MODE;
8012 MonoMethodSignature *sig = mono_method_signature (method);
8013 int i, j, type, size, out_len;
8015 if (out_args == NULL)
8017 out_len = mono_array_length (out_args);
8021 for (i = 0, j = 0; i < sig->param_count; i++) {
8022 MonoType *pt = sig->params [i];
8027 mono_error_set_execution_engine (error, "The proxy call returned an incorrect number of output arguments");
8031 arg = (char *)mono_array_get (out_args, gpointer, j);
8034 g_assert (type != MONO_TYPE_VOID);
8036 if (MONO_TYPE_IS_REFERENCE (pt)) {
8037 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
8040 MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
8041 size = mono_class_value_size (klass, NULL);
8042 if (klass->has_references)
8043 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
8045 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
8047 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
8048 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
8057 #ifndef DISABLE_REMOTING
8060 * mono_load_remote_field:
8061 * \param this pointer to an object
8062 * \param klass klass of the object containing \p field
8063 * \param field the field to load
8064 * \param res a storage to store the result
8065 * This method is called by the runtime on attempts to load fields of
8066 * transparent proxy objects. \p this points to such TP, \p klass is the class of
8067 * the object containing \p field. \p res is a storage location which can be
8068 * used to store the result.
8069 * \returns an address pointing to the value of field.
8072 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
8075 gpointer result = mono_load_remote_field_checked (this_obj, klass, field, res, &error);
8076 mono_error_cleanup (&error);
8081 * mono_load_remote_field_checked:
8082 * \param this pointer to an object
8083 * \param klass klass of the object containing \p field
8084 * \param field the field to load
8085 * \param res a storage to store the result
8086 * \param error set on error
8087 * This method is called by the runtime on attempts to load fields of
8088 * transparent proxy objects. \p this points to such TP, \p klass is the class of
8089 * the object containing \p field. \p res is a storage location which can be
8090 * used to store the result.
8091 * \returns an address pointing to the value of field. On failure returns NULL and sets \p error.
8094 mono_load_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res, MonoError *error)
8096 MONO_REQ_GC_UNSAFE_MODE;
8098 static MonoMethod *getter = NULL;
8102 MonoDomain *domain = mono_domain_get ();
8103 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8104 MonoClass *field_class;
8105 MonoMethodMessage *msg;
8106 MonoArray *out_args;
8110 g_assert (mono_object_is_transparent_proxy (this_obj));
8111 g_assert (res != NULL);
8113 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8114 mono_field_get_value (tp->rp->unwrapped_server, field, res);
8119 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
8121 mono_error_set_not_supported (error, "Linked away.");
8126 field_class = mono_class_from_mono_type (field->type);
8128 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8129 return_val_if_nok (error, NULL);
8130 out_args = mono_array_new_checked (domain, mono_defaults.object_class, 1, error);
8131 return_val_if_nok (error, NULL);
8132 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, error);
8133 return_val_if_nok (error, NULL);
8134 mono_message_init (domain, msg, rm, out_args, error);
8135 return_val_if_nok (error, NULL);
8137 full_name = mono_type_get_full_name (klass);
8138 MonoString *full_name_str = mono_string_new_checked (domain, full_name, error);
8140 return_val_if_nok (error, NULL);
8141 mono_array_setref (msg->args, 0, full_name_str);
8142 MonoString *field_name = mono_string_new_checked (domain, mono_field_get_name (field), error);
8143 return_val_if_nok (error, NULL);
8144 mono_array_setref (msg->args, 1, field_name);
8146 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8147 return_val_if_nok (error, NULL);
8150 mono_error_set_exception_instance (error, (MonoException *)exc);
8154 if (mono_array_length (out_args) == 0)
8157 mono_gc_wbarrier_generic_store (res, mono_array_get (out_args, MonoObject *, 0));
8159 if (field_class->valuetype) {
8160 return ((char *)*res) + sizeof (MonoObject);
8166 * mono_load_remote_field_new:
8170 * Missing documentation.
8173 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
8177 MonoObject *result = mono_load_remote_field_new_checked (this_obj, klass, field, &error);
8178 mono_error_cleanup (&error);
8183 * mono_load_remote_field_new_checked:
8184 * \param this pointer to an object
8185 * \param klass klass of the object containing \p field
8186 * \param field the field to load
8187 * \param error set on error.
8188 * This method is called by the runtime on attempts to load fields of
8189 * transparent proxy objects. \p this points to such TP, \p klass is the class of
8190 * the object containing \p field.
8191 * \returns a freshly allocated object containing the value of the field. On failure returns NULL and sets \p error.
8194 mono_load_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoError *error)
8196 MONO_REQ_GC_UNSAFE_MODE;
8200 static MonoMethod *tp_load = NULL;
8202 g_assert (mono_object_is_transparent_proxy (this_obj));
8205 tp_load = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "LoadRemoteFieldNew", -1);
8207 mono_error_set_not_supported (error, "Linked away.");
8212 /* MonoType *type = mono_class_get_type (klass); */
8218 return mono_runtime_invoke_checked (tp_load, this_obj, args, error);
8222 * mono_store_remote_field:
8223 * \param this_obj pointer to an object
8224 * \param klass klass of the object containing \p field
8225 * \param field the field to load
8226 * \param val the value/object to store
8227 * This method is called by the runtime on attempts to store fields of
8228 * transparent proxy objects. \p this_obj points to such TP, \p klass is the class of
8229 * the object containing \p field. \p val is the new value to store in \p field.
8232 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
8235 (void) mono_store_remote_field_checked (this_obj, klass, field, val, &error);
8236 mono_error_cleanup (&error);
8240 * mono_store_remote_field_checked:
8241 * \param this_obj pointer to an object
8242 * \param klass klass of the object containing \p field
8243 * \param field the field to load
8244 * \param val the value/object to store
8245 * \param error set on error
8246 * This method is called by the runtime on attempts to store fields of
8247 * transparent proxy objects. \p this_obj points to such TP, \p klass is the class of
8248 * the object containing \p field. \p val is the new value to store in \p field.
8249 * \returns on success returns TRUE, on failure returns FALSE and sets \p error.
8252 mono_store_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val, MonoError *error)
8255 MONO_REQ_GC_UNSAFE_MODE;
8259 MonoDomain *domain = mono_domain_get ();
8260 MonoClass *field_class;
8263 g_assert (mono_object_is_transparent_proxy (this_obj));
8265 field_class = mono_class_from_mono_type (field->type);
8267 if (field_class->valuetype) {
8268 arg = mono_value_box_checked (domain, field_class, val, error);
8269 return_val_if_nok (error, FALSE);
8271 arg = *((MonoObject**)val);
8274 return mono_store_remote_field_new_checked (this_obj, klass, field, arg, error);
8278 * mono_store_remote_field_new:
8283 * Missing documentation
8286 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
8289 (void) mono_store_remote_field_new_checked (this_obj, klass, field, arg, &error);
8290 mono_error_cleanup (&error);
8294 * mono_store_remote_field_new_checked:
8300 * Missing documentation
8303 mono_store_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg, MonoError *error)
8305 MONO_REQ_GC_UNSAFE_MODE;
8307 static MonoMethod *tp_store = NULL;
8311 g_assert (mono_object_is_transparent_proxy (this_obj));
8314 tp_store = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "StoreRemoteField", -1);
8316 mono_error_set_not_supported (error, "Linked away.");
8326 mono_runtime_invoke_checked (tp_store, this_obj, args, error);
8327 return is_ok (error);
8332 * mono_create_ftnptr:
8334 * Given a function address, create a function descriptor for it.
8335 * This is only needed on some platforms.
8338 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
8340 return callbacks.create_ftnptr (domain, addr);
8344 * mono_get_addr_from_ftnptr:
8346 * Given a pointer to a function descriptor, return the function address.
8347 * This is only needed on some platforms.
8350 mono_get_addr_from_ftnptr (gpointer descr)
8352 return callbacks.get_addr_from_ftnptr (descr);
8356 * mono_string_chars:
8357 * \param s a \c MonoString
8358 * \returns a pointer to the UTF-16 characters stored in the \c MonoString
8361 mono_string_chars (MonoString *s)
8363 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
8369 * mono_string_length:
8370 * \param s MonoString
8371 * \returns the length in characters of the string
8374 mono_string_length (MonoString *s)
8376 MONO_REQ_GC_UNSAFE_MODE;
8382 * mono_string_handle_length:
8383 * \param s \c MonoString
8384 * \returns the length in characters of the string
8387 mono_string_handle_length (MonoStringHandle s)
8389 MONO_REQ_GC_UNSAFE_MODE;
8391 return MONO_HANDLE_GETVAL (s, length);
8396 * mono_array_length:
8397 * \param array a \c MonoArray*
8398 * \returns the total number of elements in the array. This works for
8399 * both vectors and multidimensional arrays.
8402 mono_array_length (MonoArray *array)
8404 MONO_REQ_GC_UNSAFE_MODE;
8406 return array->max_length;
8410 * mono_array_addr_with_size:
8411 * \param array a \c MonoArray*
8412 * \param size size of the array elements
8413 * \param idx index into the array
8414 * Use this function to obtain the address for the \p idx item on the
8415 * \p array containing elements of size \p size.
8417 * This method performs no bounds checking or type checking.
8418 * \returns the address of the \p idx element in the array.
8421 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
8423 MONO_REQ_GC_UNSAFE_MODE;
8425 return ((char*)(array)->vector) + size * idx;
8430 mono_glist_to_array (GList *list, MonoClass *eclass, MonoError *error)
8432 MonoDomain *domain = mono_domain_get ();
8440 len = g_list_length (list);
8441 res = mono_array_new_checked (domain, eclass, len, error);
8442 return_val_if_nok (error, NULL);
8444 for (i = 0; list; list = list->next, i++)
8445 mono_array_set (res, gpointer, i, list->data);
8452 * The following section is purely to declare prototypes and
8453 * document the API, as these C files are processed by our
8459 * \param array array to alter
8460 * \param element_type A C type name, this macro will use the sizeof(type) to determine the element size
8461 * \param index index into the array
8462 * \param value value to set
8463 * Value Type version: This sets the \p index's element of the \p array
8464 * with elements of size sizeof(type) to the provided \p value.
8466 * This macro does not attempt to perform type checking or bounds checking.
8468 * Use this to set value types in a \c MonoArray.
8470 void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
8475 * mono_array_setref:
8476 * \param array array to alter
8477 * \param index index into the array
8478 * \param value value to set
8479 * Reference Type version. This sets the \p index's element of the
8480 * \p array with elements of size sizeof(type) to the provided \p value.
8482 * This macro does not attempt to perform type checking or bounds checking.
8484 * Use this to reference types in a \c MonoArray.
8486 void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
8492 * \param array array on which to operate on
8493 * \param element_type C element type (example: \c MonoString*, \c int, \c MonoObject*)
8494 * \param index index into the array
8496 * Use this macro to retrieve the \p index element of an \p array and
8497 * extract the value assuming that the elements of the array match
8498 * the provided type value.
8500 * This method can be used with both arrays holding value types and
8501 * reference types. For reference types, the \p type parameter should
8502 * be a \c MonoObject* or any subclass of it, like \c MonoString*.
8504 * This macro does not attempt to perform type checking or bounds checking.
8506 * \returns The element at the \p index position in the \p array.
8508 Type mono_array_get (MonoArray *array, Type element_type, uintptr_t index)