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 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 (domain, klass);
5261 g_assert (vtable); /* FIXME don't swallow the error */
5263 MonoObject *o = mono_object_new_specific_checked (vtable, error);
5268 * mono_object_new_pinned:
5270 * Same as mono_object_new, but the returned object will be pinned.
5271 * For SGEN, these objects will only be freed at appdomain unload.
5274 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
5276 MONO_REQ_GC_UNSAFE_MODE;
5282 vtable = mono_class_vtable (domain, klass);
5283 g_assert (vtable); /* FIXME don't swallow the error */
5285 MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
5287 if (G_UNLIKELY (!o))
5288 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
5289 else if (G_UNLIKELY (vtable->klass->has_finalize))
5290 mono_object_register_finalizer (o);
5296 * mono_object_new_specific:
5297 * \param vtable the vtable of the object that we want to create
5298 * \returns A newly created object with class and domain specified
5302 mono_object_new_specific (MonoVTable *vtable)
5305 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5306 mono_error_cleanup (&error);
5312 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
5314 MONO_REQ_GC_UNSAFE_MODE;
5320 /* check for is_com_object for COM Interop */
5321 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
5324 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
5327 MonoClass *klass = mono_class_get_activation_services_class ();
5330 mono_class_init (klass);
5332 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
5334 mono_error_set_not_supported (error, "Linked away.");
5337 vtable->domain->create_proxy_for_type_method = im;
5340 pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
5341 if (!mono_error_ok (error))
5344 o = mono_runtime_invoke_checked (im, NULL, pa, error);
5345 if (!mono_error_ok (error))
5352 return mono_object_new_alloc_specific_checked (vtable, error);
5356 ves_icall_object_new_specific (MonoVTable *vtable)
5359 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5360 mono_error_set_pending_exception (&error);
5366 * mono_object_new_alloc_specific:
5367 * \param vtable virtual table for the object.
5368 * This function allocates a new \c MonoObject with the type derived
5369 * from the \p vtable information. If the class of this object has a
5370 * finalizer, then the object will be tracked for finalization.
5372 * This method might raise an exception on errors. Use the
5373 * \c mono_object_new_fast_checked method if you want to manually raise
5376 * \returns the allocated object.
5379 mono_object_new_alloc_specific (MonoVTable *vtable)
5382 MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
5383 mono_error_cleanup (&error);
5389 * mono_object_new_alloc_specific_checked:
5390 * \param vtable virtual table for the object.
5391 * \param error holds the error return value.
5393 * This function allocates a new \c MonoObject with the type derived
5394 * from the \p vtable information. If the class of this object has a
5395 * finalizer, then the object will be tracked for finalization.
5397 * If there is not enough memory, the \p error parameter will be set
5398 * and will contain a user-visible message with the amount of bytes
5399 * that were requested.
5401 * \returns the allocated object, or NULL if there is not enough memory
5404 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
5406 MONO_REQ_GC_UNSAFE_MODE;
5412 o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5414 if (G_UNLIKELY (!o))
5415 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5416 else if (G_UNLIKELY (vtable->klass->has_finalize))
5417 mono_object_register_finalizer (o);
5423 * mono_object_new_fast:
5424 * \param vtable virtual table for the object.
5426 * This function allocates a new \c MonoObject with the type derived
5427 * from the \p vtable information. The returned object is not tracked
5428 * for finalization. If your object implements a finalizer, you should
5429 * use \c mono_object_new_alloc_specific instead.
5431 * This method might raise an exception on errors. Use the
5432 * \c mono_object_new_fast_checked method if you want to manually raise
5435 * \returns the allocated object.
5438 mono_object_new_fast (MonoVTable *vtable)
5441 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5442 mono_error_cleanup (&error);
5448 * mono_object_new_fast_checked:
5449 * \param vtable virtual table for the object.
5450 * \param error holds the error return value.
5452 * This function allocates a new \c MonoObject with the type derived
5453 * from the \p vtable information. The returned object is not tracked
5454 * for finalization. If your object implements a finalizer, you should
5455 * use \c mono_object_new_alloc_specific_checked instead.
5457 * If there is not enough memory, the \p error parameter will be set
5458 * and will contain a user-visible message with the amount of bytes
5459 * that were requested.
5461 * \returns the allocated object, or NULL if there is not enough memory
5464 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
5466 MONO_REQ_GC_UNSAFE_MODE;
5472 o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5474 if (G_UNLIKELY (!o))
5475 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5481 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
5483 MONO_REQ_GC_UNSAFE_MODE;
5489 o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
5491 if (G_UNLIKELY (!o))
5492 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5493 else if (G_UNLIKELY (vtable->klass->has_finalize))
5494 mono_object_register_finalizer (o);
5500 * mono_object_new_from_token:
5501 * \param image Context where the type_token is hosted
5502 * \param token a token of the type that we want to create
5503 * \returns A newly created object whose definition is
5504 * looked up using \p token in the \p image image
5507 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
5509 MONO_REQ_GC_UNSAFE_MODE;
5515 klass = mono_class_get_checked (image, token, &error);
5516 mono_error_assert_ok (&error);
5518 result = mono_object_new_checked (domain, klass, &error);
5520 mono_error_cleanup (&error);
5527 * mono_object_clone:
5528 * \param obj the object to clone
5529 * \returns A newly created object who is a shallow copy of \p obj
5532 mono_object_clone (MonoObject *obj)
5535 MonoObject *o = mono_object_clone_checked (obj, &error);
5536 mono_error_cleanup (&error);
5542 mono_object_clone_checked (MonoObject *obj, MonoError *error)
5544 MONO_REQ_GC_UNSAFE_MODE;
5551 size = obj->vtable->klass->instance_size;
5553 if (obj->vtable->klass->rank)
5554 return (MonoObject*)mono_array_clone_checked ((MonoArray*)obj, error);
5556 o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
5558 if (G_UNLIKELY (!o)) {
5559 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5563 /* If the object doesn't contain references this will do a simple memmove. */
5564 mono_gc_wbarrier_object_copy (o, obj);
5566 if (obj->vtable->klass->has_finalize)
5567 mono_object_register_finalizer (o);
5572 * mono_array_full_copy:
5573 * \param src source array to copy
5574 * \param dest destination array
5575 * Copies the content of one array to another with exactly the same type and size.
5578 mono_array_full_copy (MonoArray *src, MonoArray *dest)
5580 MONO_REQ_GC_UNSAFE_MODE;
5583 MonoClass *klass = src->obj.vtable->klass;
5585 g_assert (klass == dest->obj.vtable->klass);
5587 size = mono_array_length (src);
5588 g_assert (size == mono_array_length (dest));
5589 size *= mono_array_element_size (klass);
5591 array_full_copy_unchecked_size (src, dest, klass, size);
5595 array_full_copy_unchecked_size (MonoArray *src, MonoArray *dest, MonoClass *klass, uintptr_t size)
5597 if (mono_gc_is_moving ()) {
5598 if (klass->element_class->valuetype) {
5599 if (klass->element_class->has_references)
5600 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
5602 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5604 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
5607 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5612 * mono_array_clone_in_domain:
5613 * \param domain the domain in which the array will be cloned into
5614 * \param array the array to clone
5615 * \param error set on error
5616 * This routine returns a copy of the array that is hosted on the
5617 * specified \c MonoDomain. On failure returns NULL and sets \p error.
5620 mono_array_clone_in_domain (MonoDomain *domain, MonoArrayHandle array_handle, MonoError *error)
5622 MONO_REQ_GC_UNSAFE_MODE;
5624 MonoArrayHandle result = MONO_HANDLE_NEW (MonoArray, NULL);
5626 MonoClass *klass = mono_handle_class (array_handle);
5630 /* Pin source array here - if bounds is non-NULL, it's a pointer into the object data */
5631 uint32_t src_handle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, array_handle), TRUE);
5633 MonoArrayBounds *array_bounds = MONO_HANDLE_GETVAL (array_handle, bounds);
5635 if (array_bounds == NULL) {
5636 size = mono_array_handle_length (array_handle);
5637 o = mono_array_new_full_handle (domain, klass, &size, NULL, error);
5640 size *= mono_array_element_size (klass);
5642 uintptr_t *sizes = (uintptr_t *)alloca (klass->rank * sizeof (uintptr_t));
5643 intptr_t *lower_bounds = (intptr_t *)alloca (klass->rank * sizeof (intptr_t));
5644 size = mono_array_element_size (klass);
5645 for (int i = 0; i < klass->rank; ++i) {
5646 sizes [i] = array_bounds [i].length;
5647 size *= array_bounds [i].length;
5648 lower_bounds [i] = array_bounds [i].lower_bound;
5650 o = mono_array_new_full_handle (domain, klass, sizes, lower_bounds, error);
5655 uint32_t dst_handle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, o), TRUE);
5656 array_full_copy_unchecked_size (MONO_HANDLE_RAW (array_handle), MONO_HANDLE_RAW (o), klass, size);
5657 mono_gchandle_free (dst_handle);
5659 MONO_HANDLE_ASSIGN (result, o);
5662 mono_gchandle_free (src_handle);
5668 * \param array the array to clone
5669 * \returns A newly created array who is a shallow copy of \p array
5672 mono_array_clone (MonoArray *array)
5674 MONO_REQ_GC_UNSAFE_MODE;
5677 MonoArray *result = mono_array_clone_checked (array, &error);
5678 mono_error_cleanup (&error);
5683 * mono_array_clone_checked:
5684 * \param array the array to clone
5685 * \param error set on error
5686 * \returns A newly created array who is a shallow copy of \p array. On
5687 * failure returns NULL and sets \p error.
5690 mono_array_clone_checked (MonoArray *array_raw, MonoError *error)
5692 MONO_REQ_GC_UNSAFE_MODE;
5693 HANDLE_FUNCTION_ENTER ();
5694 /* FIXME: callers of mono_array_clone_checked should use handles */
5696 MONO_HANDLE_DCL (MonoArray, array);
5697 MonoArrayHandle result = mono_array_clone_in_domain (MONO_HANDLE_DOMAIN (array), array, error);
5698 HANDLE_FUNCTION_RETURN_OBJ (result);
5701 /* helper macros to check for overflow when calculating the size of arrays */
5702 #ifdef MONO_BIG_ARRAYS
5703 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
5704 #define MYGUINT_MAX MYGUINT64_MAX
5705 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5706 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
5707 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5708 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
5709 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
5711 #define MYGUINT32_MAX 4294967295U
5712 #define MYGUINT_MAX MYGUINT32_MAX
5713 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5714 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
5715 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5716 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
5717 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
5721 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
5723 MONO_REQ_GC_NEUTRAL_MODE;
5727 byte_len = mono_array_element_size (klass);
5728 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
5731 if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
5733 byte_len += MONO_SIZEOF_MONO_ARRAY;
5741 * mono_array_new_full:
5742 * \param domain domain where the object is created
5743 * \param array_class array class
5744 * \param lengths lengths for each dimension in the array
5745 * \param lower_bounds lower bounds for each dimension in the array (may be NULL)
5746 * This routine creates a new array object with the given dimensions,
5747 * lower bounds and type.
5750 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
5753 MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
5754 mono_error_cleanup (&error);
5760 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
5762 MONO_REQ_GC_UNSAFE_MODE;
5764 uintptr_t byte_len = 0, len, bounds_size;
5767 MonoArrayBounds *bounds;
5773 if (!array_class->inited)
5774 mono_class_init (array_class);
5778 /* A single dimensional array with a 0 lower bound is the same as an szarray */
5779 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
5781 if (len > MONO_ARRAY_MAX_INDEX) {
5782 mono_error_set_generic_error (error, "System", "OverflowException", "");
5787 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
5789 for (i = 0; i < array_class->rank; ++i) {
5790 if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
5791 mono_error_set_generic_error (error, "System", "OverflowException", "");
5794 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5795 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5802 if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5803 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5809 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5810 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5813 byte_len = (byte_len + 3) & ~3;
5814 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5815 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5818 byte_len += bounds_size;
5821 * Following three lines almost taken from mono_object_new ():
5822 * they need to be kept in sync.
5824 vtable = mono_class_vtable_full (domain, array_class, error);
5825 return_val_if_nok (error, NULL);
5828 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5830 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5832 if (G_UNLIKELY (!o)) {
5833 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5837 array = (MonoArray*)o;
5839 bounds = array->bounds;
5842 for (i = 0; i < array_class->rank; ++i) {
5843 bounds [i].length = lengths [i];
5845 bounds [i].lower_bound = lower_bounds [i];
5854 * \param domain domain where the object is created
5855 * \param eclass element class
5856 * \param n number of array elements
5857 * This routine creates a new szarray with \p n elements of type \p eclass.
5860 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5862 MONO_REQ_GC_UNSAFE_MODE;
5865 MonoArray *result = mono_array_new_checked (domain, eclass, n, &error);
5866 mono_error_cleanup (&error);
5871 * mono_array_new_checked:
5872 * \param domain domain where the object is created
5873 * \param eclass element class
5874 * \param n number of array elements
5875 * \param error set on error
5876 * This routine creates a new szarray with \p n elements of type \p eclass.
5877 * On failure returns NULL and sets \p error.
5880 mono_array_new_checked (MonoDomain *domain, MonoClass *eclass, uintptr_t n, MonoError *error)
5886 ac = mono_array_class_get (eclass, 1);
5889 MonoVTable *vtable = mono_class_vtable_full (domain, ac, error);
5890 return_val_if_nok (error, NULL);
5892 return mono_array_new_specific_checked (vtable, n, error);
5896 ves_icall_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5899 MonoArray *arr = mono_array_new_checked (domain, eclass, n, &error);
5900 mono_error_set_pending_exception (&error);
5906 * mono_array_new_specific:
5907 * \param vtable a vtable in the appropriate domain for an initialized class
5908 * \param n number of array elements
5909 * This routine is a fast alternative to \c mono_array_new for code which
5910 * can be sure about the domain it operates in.
5913 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5916 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5917 mono_error_cleanup (&error);
5923 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
5925 MONO_REQ_GC_UNSAFE_MODE;
5932 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
5933 mono_error_set_generic_error (error, "System", "OverflowException", "");
5937 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
5938 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5941 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
5943 if (G_UNLIKELY (!o)) {
5944 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5948 return (MonoArray*)o;
5952 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
5955 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5956 mono_error_set_pending_exception (&error);
5962 * mono_string_empty_wrapper:
5964 * Returns: The same empty string instance as the managed string.Empty
5967 mono_string_empty_wrapper (void)
5969 MonoDomain *domain = mono_domain_get ();
5970 return mono_string_empty (domain);
5974 * mono_string_empty:
5976 * Returns: The same empty string instance as the managed string.Empty
5979 mono_string_empty (MonoDomain *domain)
5982 g_assert (domain->empty_string);
5983 return domain->empty_string;
5987 * mono_string_new_utf16:
5988 * \param text a pointer to an utf16 string
5989 * \param len the length of the string
5990 * \returns A newly created string object which contains \p text.
5993 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
5995 MONO_REQ_GC_UNSAFE_MODE;
5998 MonoString *res = NULL;
5999 res = mono_string_new_utf16_checked (domain, text, len, &error);
6000 mono_error_cleanup (&error);
6006 * mono_string_new_utf16_checked:
6007 * \param text a pointer to an utf16 string
6008 * \param len the length of the string
6009 * \param error written on error.
6010 * \returns A newly created string object which contains \p text.
6011 * On error, returns NULL and sets \p error.
6014 mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
6016 MONO_REQ_GC_UNSAFE_MODE;
6022 s = mono_string_new_size_checked (domain, len, error);
6024 memcpy (mono_string_chars (s), text, len * 2);
6030 * mono_string_new_utf16_handle:
6031 * \param text a pointer to an utf16 string
6032 * \param len the length of the string
6033 * \param error written on error.
6034 * \returns A newly created string object which contains \p text.
6035 * On error, returns NULL and sets \p error.
6038 mono_string_new_utf16_handle (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
6040 return MONO_HANDLE_NEW (MonoString, mono_string_new_utf16_checked (domain, text, len, error));
6044 * mono_string_new_utf32_checked:
6045 * \param text a pointer to an utf32 string
6046 * \param len the length of the string
6047 * \param error set on failure.
6048 * \returns A newly created string object which contains \p text. On failure returns NULL and sets \p error.
6051 mono_string_new_utf32_checked (MonoDomain *domain, const mono_unichar4 *text, gint32 len, MonoError *error)
6053 MONO_REQ_GC_UNSAFE_MODE;
6056 mono_unichar2 *utf16_output = NULL;
6057 gint32 utf16_len = 0;
6058 GError *gerror = NULL;
6059 glong items_written;
6062 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
6065 g_error_free (gerror);
6067 while (utf16_output [utf16_len]) utf16_len++;
6069 s = mono_string_new_size_checked (domain, utf16_len, error);
6070 return_val_if_nok (error, NULL);
6072 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
6074 g_free (utf16_output);
6080 * mono_string_new_utf32:
6081 * \param text a pointer to a UTF-32 string
6082 * \param len the length of the string
6083 * \returns A newly created string object which contains \p text.
6086 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
6089 MonoString *result = mono_string_new_utf32_checked (domain, text, len, &error);
6090 mono_error_cleanup (&error);
6095 * mono_string_new_size:
6096 * \param text a pointer to a UTF-16 string
6097 * \param len the length of the string
6098 * \returns A newly created string object of \p len
6101 mono_string_new_size (MonoDomain *domain, gint32 len)
6104 MonoString *str = mono_string_new_size_checked (domain, len, &error);
6105 mono_error_cleanup (&error);
6111 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
6113 MONO_REQ_GC_UNSAFE_MODE;
6121 /* check for overflow */
6122 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
6123 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
6127 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
6128 g_assert (size > 0);
6130 vtable = mono_class_vtable (domain, mono_defaults.string_class);
6133 s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
6135 if (G_UNLIKELY (!s)) {
6136 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", size);
6144 * mono_string_new_len:
6145 * \param text a pointer to an utf8 string
6146 * \param length number of bytes in \p text to consider
6147 * \returns A newly created string object which contains \p text.
6150 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
6152 MONO_REQ_GC_UNSAFE_MODE;
6155 MonoString *result = mono_string_new_len_checked (domain, text, length, &error);
6156 mono_error_cleanup (&error);
6161 * mono_string_new_len_checked:
6162 * \param text a pointer to an utf8 string
6163 * \param length number of bytes in \p text to consider
6164 * \param error set on error
6165 * \returns A newly created string object which contains \p text. On
6166 * failure returns NULL and sets \p error.
6169 mono_string_new_len_checked (MonoDomain *domain, const char *text, guint length, MonoError *error)
6171 MONO_REQ_GC_UNSAFE_MODE;
6175 GError *eg_error = NULL;
6176 MonoString *o = NULL;
6178 glong items_written;
6180 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
6183 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6185 g_error_free (eg_error);
6194 * \param text a pointer to a UTF-8 string
6195 * \deprecated Use \c mono_string_new_checked in new code.
6196 * This function asserts if it cannot allocate a new string.
6197 * \returns A newly created string object which contains \p text.
6200 mono_string_new (MonoDomain *domain, const char *text)
6203 MonoString *res = NULL;
6204 res = mono_string_new_checked (domain, text, &error);
6205 mono_error_assert_ok (&error);
6210 * mono_string_new_checked:
6211 * \param text a pointer to an utf8 string
6212 * \param merror set on error
6213 * \returns A newly created string object which contains \p text.
6214 * On error returns NULL and sets \p merror.
6217 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
6219 MONO_REQ_GC_UNSAFE_MODE;
6221 GError *eg_error = NULL;
6222 MonoString *o = NULL;
6224 glong items_written;
6231 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &eg_error);
6234 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6236 mono_error_set_execution_engine (error, "String conversion error: %s", eg_error->message);
6241 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
6246 MonoString *o = NULL;
6248 if (!g_utf8_validate (text, -1, &end)) {
6249 mono_error_set_argument (error, "text", "Not a valid utf8 string");
6253 len = g_utf8_strlen (text, -1);
6254 o = mono_string_new_size_checked (domain, len, error);
6257 str = mono_string_chars (o);
6259 while (text < end) {
6260 *str++ = g_utf8_get_char (text);
6261 text = g_utf8_next_char (text);
6270 * mono_string_new_wrapper:
6271 * \param text pointer to UTF-8 characters.
6272 * Helper function to create a string object from \p text in the current domain.
6275 mono_string_new_wrapper (const char *text)
6277 MONO_REQ_GC_UNSAFE_MODE;
6279 MonoDomain *domain = mono_domain_get ();
6283 MonoString *result = mono_string_new_checked (domain, text, &error);
6284 mono_error_assert_ok (&error);
6293 * \param class the class of the value
6294 * \param value a pointer to the unboxed data
6295 * \returns A newly created object which contains \p value.
6298 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
6301 MonoObject *result = mono_value_box_checked (domain, klass, value, &error);
6302 mono_error_cleanup (&error);
6307 * mono_value_box_checked:
6308 * \param domain the domain of the new object
6309 * \param class the class of the value
6310 * \param value a pointer to the unboxed data
6311 * \param error set on error
6312 * \returns A newly created object which contains \p value. On failure
6313 * returns NULL and sets \p error.
6316 mono_value_box_checked (MonoDomain *domain, MonoClass *klass, gpointer value, MonoError *error)
6318 MONO_REQ_GC_UNSAFE_MODE;
6325 g_assert (klass->valuetype);
6326 if (mono_class_is_nullable (klass))
6327 return mono_nullable_box ((guint8 *)value, klass, error);
6329 vtable = mono_class_vtable (domain, klass);
6332 size = mono_class_instance_size (klass);
6333 res = mono_object_new_alloc_specific_checked (vtable, error);
6334 return_val_if_nok (error, NULL);
6336 size = size - sizeof (MonoObject);
6338 if (mono_gc_is_moving ()) {
6339 g_assert (size == mono_class_value_size (klass, NULL));
6340 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
6342 #if NO_UNALIGNED_ACCESS
6343 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6347 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
6350 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
6353 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
6356 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
6359 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6363 if (klass->has_finalize) {
6364 mono_object_register_finalizer (res);
6365 return_val_if_nok (error, NULL);
6372 * \param dest destination pointer
6373 * \param src source pointer
6374 * \param klass a valuetype class
6375 * Copy a valuetype from \p src to \p dest. This function must be used
6376 * when \p klass contains reference fields.
6379 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
6381 MONO_REQ_GC_UNSAFE_MODE;
6383 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
6387 * mono_value_copy_array:
6388 * \param dest destination array
6389 * \param dest_idx index in the \p dest array
6390 * \param src source pointer
6391 * \param count number of items
6392 * Copy \p count valuetype items from \p src to the array \p dest at index \p dest_idx.
6393 * This function must be used when \p klass contains references fields.
6394 * Overlap is handled.
6397 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
6399 MONO_REQ_GC_UNSAFE_MODE;
6401 int size = mono_array_element_size (dest->obj.vtable->klass);
6402 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
6403 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
6404 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
6408 * mono_object_get_domain:
6409 * \param obj object to query
6410 * \returns the \c MonoDomain where the object is hosted
6413 mono_object_get_domain (MonoObject *obj)
6415 MONO_REQ_GC_UNSAFE_MODE;
6417 return mono_object_domain (obj);
6421 * mono_object_get_class:
6422 * \param obj object to query
6423 * Use this function to obtain the \c MonoClass* for a given \c MonoObject.
6424 * \returns the \c MonoClass of the object.
6427 mono_object_get_class (MonoObject *obj)
6429 MONO_REQ_GC_UNSAFE_MODE;
6431 return mono_object_class (obj);
6434 * mono_object_get_size:
6435 * \param o object to query
6436 * \returns the size, in bytes, of \p o
6439 mono_object_get_size (MonoObject* o)
6441 MONO_REQ_GC_UNSAFE_MODE;
6443 MonoClass* klass = mono_object_class (o);
6444 if (klass == mono_defaults.string_class) {
6445 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
6446 } else if (o->vtable->rank) {
6447 MonoArray *array = (MonoArray*)o;
6448 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
6449 if (array->bounds) {
6452 size += sizeof (MonoArrayBounds) * o->vtable->rank;
6456 return mono_class_instance_size (klass);
6461 * mono_object_unbox:
6462 * \param obj object to unbox
6463 * \returns a pointer to the start of the valuetype boxed in this
6466 * This method will assert if the object passed is not a valuetype.
6469 mono_object_unbox (MonoObject *obj)
6471 MONO_REQ_GC_UNSAFE_MODE;
6473 /* add assert for valuetypes? */
6474 g_assert (obj->vtable->klass->valuetype);
6475 return ((char*)obj) + sizeof (MonoObject);
6479 * mono_object_isinst:
6480 * \param obj an object
6481 * \param klass a pointer to a class
6482 * \returns \p obj if \p obj is derived from \p klass or NULL otherwise.
6485 mono_object_isinst (MonoObject *obj_raw, MonoClass *klass)
6487 MONO_REQ_GC_UNSAFE_MODE;
6489 HANDLE_FUNCTION_ENTER ();
6490 MONO_HANDLE_DCL (MonoObject, obj);
6492 MonoObjectHandle result = mono_object_handle_isinst (obj, klass, &error);
6493 mono_error_cleanup (&error);
6494 HANDLE_FUNCTION_RETURN_OBJ (result);
6499 * mono_object_isinst_checked:
6500 * \param obj an object
6501 * \param klass a pointer to a class
6502 * \param error set on error
6503 * \returns \p obj if \p obj is derived from \p klass or NULL if it isn't.
6504 * On failure returns NULL and sets \p error.
6507 mono_object_isinst_checked (MonoObject *obj_raw, MonoClass *klass, MonoError *error)
6509 MONO_REQ_GC_UNSAFE_MODE;
6511 HANDLE_FUNCTION_ENTER ();
6513 MONO_HANDLE_DCL (MonoObject, obj);
6514 MonoObjectHandle result = mono_object_handle_isinst (obj, klass, error);
6515 HANDLE_FUNCTION_RETURN_OBJ (result);
6519 * mono_object_handle_isinst:
6520 * \param obj an object
6521 * \param klass a pointer to a class
6522 * \param error set on error
6523 * \returns \p obj if \p obj is derived from \p klass or NULL if it isn't.
6524 * On failure returns NULL and sets \p error.
6527 mono_object_handle_isinst (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
6532 mono_class_init (klass);
6534 if (mono_class_is_marshalbyref (klass) || mono_class_is_interface (klass)) {
6535 return mono_object_handle_isinst_mbyref (obj, klass, error);
6538 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6540 if (!MONO_HANDLE_IS_NULL (obj) && mono_class_is_assignable_from (klass, mono_handle_class (obj)))
6541 MONO_HANDLE_ASSIGN (result, obj);
6546 * mono_object_isinst_mbyref:
6549 mono_object_isinst_mbyref (MonoObject *obj_raw, MonoClass *klass)
6551 MONO_REQ_GC_UNSAFE_MODE;
6553 HANDLE_FUNCTION_ENTER ();
6555 MONO_HANDLE_DCL (MonoObject, obj);
6556 MonoObjectHandle result = mono_object_handle_isinst_mbyref (obj, klass, &error);
6557 mono_error_cleanup (&error); /* FIXME better API that doesn't swallow the error */
6558 HANDLE_FUNCTION_RETURN_OBJ (result);
6562 mono_object_handle_isinst_mbyref (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
6566 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6568 if (MONO_HANDLE_IS_NULL (obj))
6571 MonoVTable *vt = MONO_HANDLE_GETVAL (obj, vtable);
6573 if (mono_class_is_interface (klass)) {
6574 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
6575 MONO_HANDLE_ASSIGN (result, obj);
6579 /* casting an array one of the invariant interfaces that must act as such */
6580 if (klass->is_array_special_interface) {
6581 if (mono_class_is_assignable_from (klass, vt->klass)) {
6582 MONO_HANDLE_ASSIGN (result, obj);
6587 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
6588 else if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, mono_handle_class (obj))) {
6589 MONO_HANDLE_ASSIGN (result, obj);
6593 MonoClass *oklass = vt->klass;
6594 if (mono_class_is_transparent_proxy (oklass)){
6595 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), remote_class);
6596 oklass = remote_class->proxy_class;
6599 mono_class_setup_supertypes (klass);
6600 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass)) {
6601 MONO_HANDLE_ASSIGN (result, obj);
6605 #ifndef DISABLE_REMOTING
6606 if (mono_class_is_transparent_proxy (vt->klass))
6608 MonoBoolean custom_type_info = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), custom_type_info);
6609 if (!custom_type_info)
6611 MonoDomain *domain = mono_domain_get ();
6612 MonoObjectHandle rp = MONO_HANDLE_NEW (MonoObject, NULL);
6613 MONO_HANDLE_GET (rp, MONO_HANDLE_CAST (MonoTransparentProxy, obj), rp);
6614 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
6615 MonoMethod *im = NULL;
6618 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
6620 mono_error_set_not_supported (error, "Linked away.");
6623 im = mono_object_handle_get_virtual_method (rp, im, error);
6628 MonoReflectionTypeHandle reftype = mono_type_get_object_handle (domain, &klass->byval_arg, error);
6632 pa [0] = MONO_HANDLE_RAW (reftype);
6633 pa [1] = MONO_HANDLE_RAW (obj);
6634 MonoObject *res = mono_runtime_invoke_checked (im, MONO_HANDLE_RAW (rp), pa, error);
6638 if (*(MonoBoolean *) mono_object_unbox(res)) {
6639 /* Update the vtable of the remote type, so it can safely cast to this new type */
6640 mono_upgrade_remote_class (domain, obj, klass, error);
6643 MONO_HANDLE_ASSIGN (result, obj);
6646 #endif /* DISABLE_REMOTING */
6652 * mono_object_castclass_mbyref:
6653 * \param obj an object
6654 * \param klass a pointer to a class
6655 * \returns \p obj if \p obj is derived from \p klass, returns NULL otherwise.
6658 mono_object_castclass_mbyref (MonoObject *obj_raw, MonoClass *klass)
6660 MONO_REQ_GC_UNSAFE_MODE;
6661 HANDLE_FUNCTION_ENTER ();
6663 MONO_HANDLE_DCL (MonoObject, obj);
6664 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6665 if (MONO_HANDLE_IS_NULL (obj))
6667 MONO_HANDLE_ASSIGN (result, mono_object_handle_isinst_mbyref (obj, klass, &error));
6668 mono_error_cleanup (&error);
6670 HANDLE_FUNCTION_RETURN_OBJ (result);
6674 MonoDomain *orig_domain;
6680 str_lookup (MonoDomain *domain, gpointer user_data)
6682 MONO_REQ_GC_UNSAFE_MODE;
6684 LDStrInfo *info = (LDStrInfo *)user_data;
6685 if (info->res || domain == info->orig_domain)
6687 info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
6691 mono_string_get_pinned (MonoString *str, MonoError *error)
6693 MONO_REQ_GC_UNSAFE_MODE;
6697 /* We only need to make a pinned version of a string if this is a moving GC */
6698 if (!mono_gc_is_moving ())
6702 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
6703 news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
6705 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
6706 news->length = mono_string_length (str);
6708 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6714 mono_string_is_interned_lookup (MonoString *str, int insert, MonoError *error)
6716 MONO_REQ_GC_UNSAFE_MODE;
6718 MonoGHashTable *ldstr_table;
6719 MonoString *s, *res;
6724 domain = ((MonoObject *)str)->vtable->domain;
6725 ldstr_table = domain->ldstr_table;
6727 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6733 /* Allocate outside the lock */
6735 s = mono_string_get_pinned (str, error);
6736 return_val_if_nok (error, NULL);
6739 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6744 mono_g_hash_table_insert (ldstr_table, s, s);
6749 LDStrInfo ldstr_info;
6750 ldstr_info.orig_domain = domain;
6751 ldstr_info.ins = str;
6752 ldstr_info.res = NULL;
6754 mono_domain_foreach (str_lookup, &ldstr_info);
6755 if (ldstr_info.res) {
6757 * the string was already interned in some other domain:
6758 * intern it in the current one as well.
6760 mono_g_hash_table_insert (ldstr_table, str, str);
6770 * mono_string_is_interned:
6771 * \param o String to probe
6772 * \returns Whether the string has been interned.
6775 mono_string_is_interned (MonoString *o)
6778 MonoString *result = mono_string_is_interned_lookup (o, FALSE, &error);
6779 /* This function does not fail. */
6780 mono_error_assert_ok (&error);
6785 * mono_string_intern:
6786 * \param o String to intern
6787 * Interns the string passed.
6788 * \returns The interned string.
6791 mono_string_intern (MonoString *str)
6794 MonoString *result = mono_string_intern_checked (str, &error);
6795 mono_error_assert_ok (&error);
6800 * mono_string_intern_checked:
6801 * \param o String to intern
6802 * \param error set on error.
6803 * Interns the string passed.
6804 * \returns The interned string. On failure returns NULL and sets \p error
6807 mono_string_intern_checked (MonoString *str, MonoError *error)
6809 MONO_REQ_GC_UNSAFE_MODE;
6813 return mono_string_is_interned_lookup (str, TRUE, error);
6818 * \param domain the domain where the string will be used.
6819 * \param image a metadata context
6820 * \param idx index into the user string table.
6821 * Implementation for the \c ldstr opcode.
6822 * \returns a loaded string from the \p image / \p idx combination.
6825 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
6828 MonoString *result = mono_ldstr_checked (domain, image, idx, &error);
6829 mono_error_cleanup (&error);
6834 * mono_ldstr_checked:
6835 * \param domain the domain where the string will be used.
6836 * \param image a metadata context
6837 * \param idx index into the user string table.
6838 * \param error set on error.
6839 * Implementation for the \c ldstr opcode.
6840 * \returns A loaded string from the \p image / \p idx combination.
6841 * On failure returns NULL and sets \p error.
6844 mono_ldstr_checked (MonoDomain *domain, MonoImage *image, guint32 idx, MonoError *error)
6846 MONO_REQ_GC_UNSAFE_MODE;
6849 if (image->dynamic) {
6850 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL, error);
6853 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6854 return NULL; /*FIXME we should probably be raising an exception here*/
6855 MonoString *str = mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx), error);
6861 * mono_ldstr_metadata_sig
6862 * \param domain the domain for the string
6863 * \param sig the signature of a metadata string
6864 * \param error set on error
6865 * \returns a \c MonoString for a string stored in the metadata. On
6866 * failure returns NULL and sets \p error.
6869 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error)
6871 MONO_REQ_GC_UNSAFE_MODE;
6874 const char *str = sig;
6875 MonoString *o, *interned;
6878 len2 = mono_metadata_decode_blob_size (str, &str);
6881 o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, error);
6882 return_val_if_nok (error, NULL);
6883 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
6886 guint16 *p2 = (guint16*)mono_string_chars (o);
6887 for (i = 0; i < len2; ++i) {
6888 *p2 = GUINT16_FROM_LE (*p2);
6894 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6897 return interned; /* o will get garbage collected */
6899 o = mono_string_get_pinned (o, error);
6902 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6904 mono_g_hash_table_insert (domain->ldstr_table, o, o);
6916 * Same as mono_ldstr, but return a NULL terminated utf8 string instead
6920 mono_ldstr_utf8 (MonoImage *image, guint32 idx, MonoError *error)
6926 GError *gerror = NULL;
6930 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6931 return NULL; /*FIXME we should probably be raising an exception here*/
6932 str = mono_metadata_user_string (image, idx);
6934 len2 = mono_metadata_decode_blob_size (str, &str);
6937 as = g_utf16_to_utf8 ((guint16*)str, len2, NULL, &written, &gerror);
6939 mono_error_set_argument (error, "string", "%s", gerror->message);
6940 g_error_free (gerror);
6943 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6944 if (len2 > written) {
6945 /* allocate the total length and copy the part of the string that has been converted */
6946 char *as2 = (char *)g_malloc0 (len2);
6947 memcpy (as2, as, written);
6956 * mono_string_to_utf8:
6957 * \param s a \c System.String
6958 * \deprecated Use \c mono_string_to_utf8_checked to avoid having an exception arbitrarily raised.
6959 * \returns the UTF-8 representation for \p s.
6960 * The resulting buffer needs to be freed with \c mono_free().
6963 mono_string_to_utf8 (MonoString *s)
6965 MONO_REQ_GC_UNSAFE_MODE;
6968 char *result = mono_string_to_utf8_checked (s, &error);
6970 if (!is_ok (&error)) {
6971 mono_error_cleanup (&error);
6978 * mono_string_to_utf8_checked:
6979 * \param s a \c System.String
6980 * \param error a \c MonoError.
6981 * Converts a \c MonoString to its UTF-8 representation. May fail; check
6982 * \p error to determine whether the conversion was successful.
6983 * The resulting buffer should be freed with \c mono_free().
6986 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
6988 MONO_REQ_GC_UNSAFE_MODE;
6992 GError *gerror = NULL;
7000 return g_strdup ("");
7002 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
7004 mono_error_set_argument (error, "string", "%s", gerror->message);
7005 g_error_free (gerror);
7008 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
7009 if (s->length > written) {
7010 /* allocate the total length and copy the part of the string that has been converted */
7011 char *as2 = (char *)g_malloc0 (s->length);
7012 memcpy (as2, as, written);
7021 mono_string_handle_to_utf8 (MonoStringHandle s, MonoError *error)
7023 return mono_string_to_utf8_checked (MONO_HANDLE_RAW (s), error);
7027 * mono_string_to_utf8_ignore:
7028 * \param s a MonoString
7029 * Converts a \c MonoString to its UTF-8 representation. Will ignore
7030 * invalid surrogate pairs.
7031 * The resulting buffer should be freed with \c mono_free().
7034 mono_string_to_utf8_ignore (MonoString *s)
7036 MONO_REQ_GC_UNSAFE_MODE;
7045 return g_strdup ("");
7047 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
7049 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
7050 if (s->length > written) {
7051 /* allocate the total length and copy the part of the string that has been converted */
7052 char *as2 = (char *)g_malloc0 (s->length);
7053 memcpy (as2, as, written);
7062 * mono_string_to_utf8_image_ignore:
7063 * \param s a \c System.String
7064 * Same as \c mono_string_to_utf8_ignore, but allocate the string from the image mempool.
7067 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
7069 MONO_REQ_GC_UNSAFE_MODE;
7071 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
7075 * mono_string_to_utf8_mp_ignore:
7076 * \param s a \c System.String
7077 * Same as \c mono_string_to_utf8_ignore, but allocate the string from a mempool.
7080 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
7082 MONO_REQ_GC_UNSAFE_MODE;
7084 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
7089 * mono_string_to_utf16:
7090 * \param s a \c MonoString
7091 * \returns a null-terminated array of the UTF-16 chars
7092 * contained in \p s. The result must be freed with \c g_free().
7093 * This is a temporary helper until our string implementation
7094 * is reworked to always include the null-terminating char.
7097 mono_string_to_utf16 (MonoString *s)
7099 MONO_REQ_GC_UNSAFE_MODE;
7106 as = (char *)g_malloc ((s->length * 2) + 2);
7107 as [(s->length * 2)] = '\0';
7108 as [(s->length * 2) + 1] = '\0';
7111 return (gunichar2 *)(as);
7114 memcpy (as, mono_string_chars(s), s->length * 2);
7115 return (gunichar2 *)(as);
7119 * mono_string_to_utf32:
7120 * \param s a \c MonoString
7121 * \returns a null-terminated array of the UTF-32 (UCS-4) chars
7122 * contained in \p s. The result must be freed with \c g_free().
7125 mono_string_to_utf32 (MonoString *s)
7127 MONO_REQ_GC_UNSAFE_MODE;
7129 mono_unichar4 *utf32_output = NULL;
7130 GError *error = NULL;
7131 glong items_written;
7136 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
7139 g_error_free (error);
7141 return utf32_output;
7145 * mono_string_from_utf16:
7146 * \param data the UTF-16 string (LPWSTR) to convert
7147 * Converts a NULL-terminated UTF-16 string (LPWSTR) to a \c MonoString.
7148 * \returns a \c MonoString.
7151 mono_string_from_utf16 (gunichar2 *data)
7154 MonoString *result = mono_string_from_utf16_checked (data, &error);
7155 mono_error_cleanup (&error);
7160 * mono_string_from_utf16_checked:
7161 * \param data the UTF-16 string (LPWSTR) to convert
7162 * \param error set on error
7163 * Converts a NULL-terminated UTF-16 string (LPWSTR) to a \c MonoString.
7164 * \returns a \c MonoString. On failure sets \p error and returns NULL.
7167 mono_string_from_utf16_checked (gunichar2 *data, MonoError *error)
7170 MONO_REQ_GC_UNSAFE_MODE;
7173 MonoDomain *domain = mono_domain_get ();
7179 while (data [len]) len++;
7181 return mono_string_new_utf16_checked (domain, data, len, error);
7185 * mono_string_from_utf32:
7186 * \param data the UTF-32 string (LPWSTR) to convert
7187 * Converts a UTF-32 (UCS-4) string to a \c MonoString.
7188 * \returns a \c MonoString.
7191 mono_string_from_utf32 (mono_unichar4 *data)
7194 MonoString *result = mono_string_from_utf32_checked (data, &error);
7195 mono_error_cleanup (&error);
7200 * mono_string_from_utf32_checked:
7201 * \param data the UTF-32 string (LPWSTR) to convert
7202 * \param error set on error
7203 * Converts a UTF-32 (UCS-4) string to a \c MonoString.
7204 * \returns a \c MonoString. On failure returns NULL and sets \p error.
7207 mono_string_from_utf32_checked (mono_unichar4 *data, MonoError *error)
7209 MONO_REQ_GC_UNSAFE_MODE;
7212 MonoString* result = NULL;
7213 mono_unichar2 *utf16_output = NULL;
7214 GError *gerror = NULL;
7215 glong items_written;
7221 while (data [len]) len++;
7223 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &gerror);
7226 g_error_free (gerror);
7228 result = mono_string_from_utf16_checked (utf16_output, error);
7229 g_free (utf16_output);
7234 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
7236 MONO_REQ_GC_UNSAFE_MODE;
7243 r = mono_string_to_utf8_ignore (s);
7245 r = mono_string_to_utf8_checked (s, error);
7246 if (!mono_error_ok (error))
7253 len = strlen (r) + 1;
7255 mp_s = (char *)mono_mempool_alloc (mp, len);
7257 mp_s = (char *)mono_image_alloc (image, len);
7259 memcpy (mp_s, r, len);
7267 * mono_string_to_utf8_image:
7268 * \param s a \c System.String
7269 * Same as \c mono_string_to_utf8, but allocate the string from the image mempool.
7272 mono_string_to_utf8_image (MonoImage *image, MonoStringHandle s, MonoError *error)
7274 MONO_REQ_GC_UNSAFE_MODE;
7276 return mono_string_to_utf8_internal (NULL, image, MONO_HANDLE_RAW (s), FALSE, error); /* FIXME pin the string */
7280 * mono_string_to_utf8_mp:
7281 * \param s a \c System.String
7282 * Same as \c mono_string_to_utf8, but allocate the string from a mempool.
7285 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
7287 MONO_REQ_GC_UNSAFE_MODE;
7289 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
7293 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
7296 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
7298 eh_callbacks = *cbs;
7301 MonoRuntimeExceptionHandlingCallbacks *
7302 mono_get_eh_callbacks (void)
7304 return &eh_callbacks;
7308 * mono_raise_exception:
7309 * \param ex exception object
7310 * Signal the runtime that the exception \p ex has been raised in unmanaged code.
7313 mono_raise_exception (MonoException *ex)
7315 MONO_REQ_GC_UNSAFE_MODE;
7318 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
7319 * that will cause gcc to omit the function epilog, causing problems when
7320 * the JIT tries to walk the stack, since the return address on the stack
7321 * will point into the next function in the executable, not this one.
7323 eh_callbacks.mono_raise_exception (ex);
7327 * mono_raise_exception:
7328 * \param ex exception object
7329 * Signal the runtime that the exception \p ex has been raised in unmanaged code.
7332 mono_reraise_exception (MonoException *ex)
7334 MONO_REQ_GC_UNSAFE_MODE;
7337 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
7338 * that will cause gcc to omit the function epilog, causing problems when
7339 * the JIT tries to walk the stack, since the return address on the stack
7340 * will point into the next function in the executable, not this one.
7342 eh_callbacks.mono_reraise_exception (ex);
7346 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
7348 MONO_REQ_GC_UNSAFE_MODE;
7350 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
7354 * mono_wait_handle_new:
7355 * \param domain Domain where the object will be created
7356 * \param handle Handle for the wait handle
7357 * \param error set on error.
7358 * \returns A new \c MonoWaitHandle created in the given domain for the
7359 * given handle. On failure returns NULL and sets \p error.
7362 mono_wait_handle_new (MonoDomain *domain, HANDLE handle, MonoError *error)
7364 MONO_REQ_GC_UNSAFE_MODE;
7366 MonoWaitHandle *res;
7367 gpointer params [1];
7368 static MonoMethod *handle_set;
7371 res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, error);
7372 return_val_if_nok (error, NULL);
7374 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
7376 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
7378 params [0] = &handle;
7380 mono_runtime_invoke_checked (handle_set, res, params, error);
7385 mono_wait_handle_get_handle (MonoWaitHandle *handle)
7387 MONO_REQ_GC_UNSAFE_MODE;
7389 static MonoClassField *f_safe_handle = NULL;
7392 if (!f_safe_handle) {
7393 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safeWaitHandle");
7394 g_assert (f_safe_handle);
7397 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
7403 mono_runtime_capture_context (MonoDomain *domain, MonoError *error)
7405 MONO_REQ_GC_UNSAFE_MODE;
7407 RuntimeInvokeFunction runtime_invoke;
7411 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
7412 MonoMethod *method = mono_get_context_capture_method ();
7413 MonoMethod *wrapper;
7416 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
7417 domain->capture_context_runtime_invoke = mono_compile_method_checked (wrapper, error);
7418 return_val_if_nok (error, NULL);
7419 domain->capture_context_method = mono_compile_method_checked (method, error);
7420 return_val_if_nok (error, NULL);
7423 runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
7425 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
7428 * mono_async_result_new:
7429 * \param domain domain where the object will be created.
7430 * \param handle wait handle.
7431 * \param state state to pass to AsyncResult
7432 * \param data C closure data.
7433 * \param error set on error.
7434 * Creates a new MonoAsyncResult (\c AsyncResult C# class) in the given domain.
7435 * If the handle is not null, the handle is initialized to a \c MonoWaitHandle.
7436 * On failure returns NULL and sets \p error.
7439 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data, MonoError *error)
7441 MONO_REQ_GC_UNSAFE_MODE;
7444 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, error);
7445 return_val_if_nok (error, NULL);
7446 MonoObject *context = mono_runtime_capture_context (domain, error);
7447 return_val_if_nok (error, NULL);
7448 /* we must capture the execution context from the original thread */
7450 MONO_OBJECT_SETREF (res, execution_context, context);
7451 /* note: result may be null if the flow is suppressed */
7454 res->data = (void **)data;
7455 MONO_OBJECT_SETREF (res, object_data, object_data);
7456 MONO_OBJECT_SETREF (res, async_state, state);
7457 MonoWaitHandle *wait_handle = mono_wait_handle_new (domain, handle, error);
7458 return_val_if_nok (error, NULL);
7460 MONO_OBJECT_SETREF (res, handle, (MonoObject *) wait_handle);
7462 res->sync_completed = FALSE;
7463 res->completed = FALSE;
7469 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
7471 MONO_REQ_GC_UNSAFE_MODE;
7478 g_assert (ares->async_delegate);
7480 ac = (MonoAsyncCall*) ares->object_data;
7482 res = mono_runtime_delegate_invoke_checked (ares->async_delegate, (void**) &ares->async_state, &error);
7483 if (mono_error_set_pending_exception (&error))
7486 gpointer wait_event = NULL;
7488 ac->msg->exc = NULL;
7490 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args, &error);
7492 /* The exit side of the invoke must not be aborted as it would leave the runtime in an undefined state */
7493 mono_threads_begin_abort_protected_block ();
7495 if (!ac->msg->exc) {
7496 MonoException *ex = mono_error_convert_to_exception (&error);
7497 ac->msg->exc = (MonoObject *)ex;
7499 mono_error_cleanup (&error);
7502 MONO_OBJECT_SETREF (ac, res, res);
7504 mono_monitor_enter ((MonoObject*) ares);
7505 ares->completed = 1;
7507 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
7508 mono_monitor_exit ((MonoObject*) ares);
7510 if (wait_event != NULL)
7511 mono_w32event_set (wait_event);
7513 error_init (&error); //the else branch would leave it in an undefined state
7515 mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
7517 mono_threads_end_abort_protected_block ();
7519 if (mono_error_set_pending_exception (&error))
7527 mono_message_init (MonoDomain *domain,
7528 MonoMethodMessage *this_obj,
7529 MonoReflectionMethod *method,
7530 MonoArray *out_args,
7533 MONO_REQ_GC_UNSAFE_MODE;
7535 static MonoMethod *init_message_method = NULL;
7537 if (!init_message_method) {
7538 init_message_method = mono_class_get_method_from_name (mono_defaults.mono_method_message_class, "InitMessage", 2);
7539 g_assert (init_message_method != NULL);
7543 /* FIXME set domain instead? */
7544 g_assert (domain == mono_domain_get ());
7551 mono_runtime_invoke_checked (init_message_method, this_obj, args, error);
7552 return is_ok (error);
7555 #ifndef DISABLE_REMOTING
7557 * mono_remoting_invoke:
7558 * \param real_proxy pointer to a \c RealProxy object
7559 * \param msg The \c MonoMethodMessage to execute
7560 * \param exc used to store exceptions
7561 * \param out_args used to store output arguments
7562 * This is used to call \c RealProxy::Invoke(). \c RealProxy::Invoke() returns an
7563 * \c IMessage interface and it is not trivial to extract results from there. So
7564 * we call an helper method \c PrivateInvoke instead of calling
7565 * \c RealProxy::Invoke() directly.
7566 * \returns the result object.
7569 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, MonoObject **exc, MonoArray **out_args, MonoError *error)
7571 MONO_REQ_GC_UNSAFE_MODE;
7574 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
7581 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
7584 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
7586 mono_error_set_not_supported (error, "Linked away.");
7589 real_proxy->vtable->domain->private_invoke_method = im;
7592 pa [0] = real_proxy;
7597 o = mono_runtime_try_invoke (im, NULL, pa, exc, error);
7598 return_val_if_nok (error, NULL);
7605 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
7606 MonoObject **exc, MonoArray **out_args, MonoError *error)
7608 MONO_REQ_GC_UNSAFE_MODE;
7610 static MonoClass *object_array_klass;
7615 MonoMethodSignature *sig;
7617 int i, j, outarg_count = 0;
7619 #ifndef DISABLE_REMOTING
7620 if (target && mono_object_is_transparent_proxy (target)) {
7621 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
7622 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7623 target = tp->rp->unwrapped_server;
7625 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args, error);
7630 domain = mono_domain_get ();
7631 method = msg->method->method;
7632 sig = mono_method_signature (method);
7634 for (i = 0; i < sig->param_count; i++) {
7635 if (sig->params [i]->byref)
7639 if (!object_array_klass) {
7642 klass = mono_array_class_get (mono_defaults.object_class, 1);
7645 mono_memory_barrier ();
7646 object_array_klass = klass;
7649 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, error);
7650 return_val_if_nok (error, NULL);
7652 mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
7655 MonoObject *ret = mono_runtime_try_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc, error);
7656 return_val_if_nok (error, NULL);
7658 for (i = 0, j = 0; i < sig->param_count; i++) {
7659 if (sig->params [i]->byref) {
7661 arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
7662 mono_array_setref (*out_args, j, arg);
7671 * prepare_to_string_method:
7673 * @target: Set to @obj or unboxed value if a valuetype
7675 * Returns: the ToString override for @obj. If @obj is a valuetype, @target is unboxed otherwise it's @obj.
7678 prepare_to_string_method (MonoObject *obj, void **target)
7680 MONO_REQ_GC_UNSAFE_MODE;
7682 static MonoMethod *to_string = NULL;
7690 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
7692 method = mono_object_get_virtual_method (obj, to_string);
7694 // Unbox value type if needed
7695 if (mono_class_is_valuetype (mono_method_get_class (method))) {
7696 *target = mono_object_unbox (obj);
7702 * mono_object_to_string:
7703 * \param obj The object
7704 * \param exc Any exception thrown by \c ToString. May be NULL.
7705 * \returns the result of calling \c ToString on an object.
7708 mono_object_to_string (MonoObject *obj, MonoObject **exc)
7711 MonoString *s = NULL;
7713 MonoMethod *method = prepare_to_string_method (obj, &target);
7715 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
7716 if (*exc == NULL && !mono_error_ok (&error))
7717 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
7719 mono_error_cleanup (&error);
7721 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
7722 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
7729 * mono_object_to_string_checked:
7730 * \param obj The object
7731 * \param error Set on error.
7732 * \returns the result of calling \c ToString() on an object. If the
7733 * method cannot be invoked or if it raises an exception, sets \p error
7737 mono_object_to_string_checked (MonoObject *obj, MonoError *error)
7741 MonoMethod *method = prepare_to_string_method (obj, &target);
7742 return (MonoString*) mono_runtime_invoke_checked (method, target, NULL, error);
7746 * mono_object_try_to_string:
7747 * \param obj The object
7748 * \param exc Any exception thrown by \c ToString(). Must not be NULL.
7749 * \param error Set if method cannot be invoked.
7750 * \returns the result of calling \c ToString() on an object. If the
7751 * method cannot be invoked sets \p error, if it raises an exception sets \p exc,
7755 mono_object_try_to_string (MonoObject *obj, MonoObject **exc, MonoError *error)
7760 MonoMethod *method = prepare_to_string_method (obj, &target);
7761 return (MonoString*) mono_runtime_try_invoke (method, target, NULL, exc, error);
7767 get_native_backtrace (MonoException *exc_raw)
7769 HANDLE_FUNCTION_ENTER ();
7770 MONO_HANDLE_DCL(MonoException, exc);
7771 char * trace = mono_exception_handle_get_native_backtrace (exc);
7772 HANDLE_FUNCTION_RETURN_VAL (trace);
7776 * mono_print_unhandled_exception:
7777 * \param exc The exception
7778 * Prints the unhandled exception.
7781 mono_print_unhandled_exception (MonoObject *exc)
7783 MONO_REQ_GC_UNSAFE_MODE;
7786 char *message = (char*)"";
7787 gboolean free_message = FALSE;
7790 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
7791 message = g_strdup ("OutOfMemoryException");
7792 free_message = TRUE;
7793 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
7794 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
7795 free_message = TRUE;
7798 if (((MonoException*)exc)->native_trace_ips) {
7799 message = get_native_backtrace ((MonoException*)exc);
7800 free_message = TRUE;
7802 MonoObject *other_exc = NULL;
7803 str = mono_object_try_to_string (exc, &other_exc, &error);
7804 if (other_exc == NULL && !is_ok (&error))
7805 other_exc = (MonoObject*)mono_error_convert_to_exception (&error);
7807 mono_error_cleanup (&error);
7809 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
7810 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
7812 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
7813 original_backtrace, nested_backtrace);
7815 g_free (original_backtrace);
7816 g_free (nested_backtrace);
7817 free_message = TRUE;
7819 message = mono_string_to_utf8_checked (str, &error);
7820 if (!mono_error_ok (&error)) {
7821 mono_error_cleanup (&error);
7822 message = (char *) "";
7824 free_message = TRUE;
7831 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
7832 * exc->vtable->klass->name, message);
7834 g_printerr ("\nUnhandled Exception:\n%s\n", message);
7841 * mono_delegate_ctor_with_method:
7842 * \param this pointer to an uninitialized delegate object
7843 * \param target target object
7844 * \param addr pointer to native code
7845 * \param method method
7846 * \param error set on error.
7847 * Initialize a delegate and sets a specific method, not the one
7848 * associated with \p addr. This is useful when sharing generic code.
7849 * In that case \p addr will most probably not be associated with the
7850 * correct instantiation of the method.
7851 * On failure returns FALSE and sets \p error.
7854 mono_delegate_ctor_with_method (MonoObjectHandle this_obj, MonoObjectHandle target, gpointer addr, MonoMethod *method, MonoError *error)
7856 MONO_REQ_GC_UNSAFE_MODE;
7859 MonoDelegateHandle delegate = MONO_HANDLE_CAST (MonoDelegate, this_obj);
7861 g_assert (!MONO_HANDLE_IS_NULL (this_obj));
7864 MonoClass *klass = mono_handle_class (this_obj);
7865 g_assert (mono_class_has_parent (klass, mono_defaults.multicastdelegate_class));
7868 MONO_HANDLE_SETVAL (delegate, method, MonoMethod*, method);
7870 UnlockedIncrement (&mono_stats.delegate_creations);
7872 #ifndef DISABLE_REMOTING
7873 if (!MONO_HANDLE_IS_NULL (target) && mono_class_is_transparent_proxy (mono_handle_class (target))) {
7875 method = mono_marshal_get_remoting_invoke (method);
7876 #ifdef ENABLE_INTERPRETER
7877 //g_error ("need RuntimeMethod in method_ptr when using interpreter");
7879 MONO_HANDLE_SETVAL (delegate, method_ptr, gpointer, mono_compile_method_checked (method, error));
7880 return_val_if_nok (error, FALSE);
7881 MONO_HANDLE_SET (delegate, target, target);
7885 MONO_HANDLE_SETVAL (delegate, method_ptr, gpointer, addr);
7886 MONO_HANDLE_SET (delegate, target, target);
7889 MONO_HANDLE_SETVAL (delegate, invoke_impl, gpointer, callbacks.create_delegate_trampoline (MONO_HANDLE_DOMAIN (delegate), mono_handle_class (delegate)));
7890 if (callbacks.init_delegate)
7891 callbacks.init_delegate (MONO_HANDLE_RAW (delegate)); /* FIXME: update init_delegate callback to take a MonoDelegateHandle */
7896 * mono_delegate_ctor:
7897 * \param this pointer to an uninitialized delegate object
7898 * \param target target object
7899 * \param addr pointer to native code
7900 * \param error set on error.
7901 * This is used to initialize a delegate.
7902 * On failure returns FALSE and sets \p error.
7905 mono_delegate_ctor (MonoObjectHandle this_obj, MonoObjectHandle target, gpointer addr, MonoError *error)
7907 MONO_REQ_GC_UNSAFE_MODE;
7910 MonoDomain *domain = mono_domain_get ();
7912 MonoMethod *method = NULL;
7916 ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
7918 if (!ji && domain != mono_get_root_domain ())
7919 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
7921 method = mono_jit_info_get_method (ji);
7922 g_assert (!mono_class_is_gtd (method->klass));
7925 return mono_delegate_ctor_with_method (this_obj, target, addr, method, error);
7929 * mono_method_call_message_new:
7930 * \param method method to encapsulate
7931 * \param params parameters to the method
7932 * \param invoke optional, delegate invoke.
7933 * \param cb async callback delegate.
7934 * \param state state passed to the async callback.
7935 * \param error set on error.
7936 * Translates arguments pointers into a \c MonoMethodMessage.
7937 * On failure returns NULL and sets \p error.
7940 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
7941 MonoDelegate **cb, MonoObject **state, MonoError *error)
7943 MONO_REQ_GC_UNSAFE_MODE;
7947 MonoDomain *domain = mono_domain_get ();
7948 MonoMethodSignature *sig = mono_method_signature (method);
7949 MonoMethodMessage *msg;
7952 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
7953 return_val_if_nok (error, NULL);
7956 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, error);
7957 return_val_if_nok (error, NULL);
7958 mono_message_init (domain, msg, rm, NULL, error);
7959 return_val_if_nok (error, NULL);
7960 count = sig->param_count - 2;
7962 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
7963 return_val_if_nok (error, NULL);
7964 mono_message_init (domain, msg, rm, NULL, error);
7965 return_val_if_nok (error, NULL);
7966 count = sig->param_count;
7969 for (i = 0; i < count; i++) {
7974 if (sig->params [i]->byref)
7975 vpos = *((gpointer *)params [i]);
7979 klass = mono_class_from_mono_type (sig->params [i]);
7981 if (klass->valuetype) {
7982 arg = mono_value_box_checked (domain, klass, vpos, error);
7983 return_val_if_nok (error, NULL);
7985 arg = *((MonoObject **)vpos);
7987 mono_array_setref (msg->args, i, arg);
7990 if (cb != NULL && state != NULL) {
7991 *cb = *((MonoDelegate **)params [i]);
7993 *state = *((MonoObject **)params [i]);
8000 * mono_method_return_message_restore:
8002 * Restore results from message based processing back to arguments pointers
8005 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args, MonoError *error)
8007 MONO_REQ_GC_UNSAFE_MODE;
8011 MonoMethodSignature *sig = mono_method_signature (method);
8012 int i, j, type, size, out_len;
8014 if (out_args == NULL)
8016 out_len = mono_array_length (out_args);
8020 for (i = 0, j = 0; i < sig->param_count; i++) {
8021 MonoType *pt = sig->params [i];
8026 mono_error_set_execution_engine (error, "The proxy call returned an incorrect number of output arguments");
8030 arg = (char *)mono_array_get (out_args, gpointer, j);
8033 g_assert (type != MONO_TYPE_VOID);
8035 if (MONO_TYPE_IS_REFERENCE (pt)) {
8036 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
8039 MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
8040 size = mono_class_value_size (klass, NULL);
8041 if (klass->has_references)
8042 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
8044 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
8046 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
8047 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
8056 #ifndef DISABLE_REMOTING
8059 * mono_load_remote_field:
8060 * \param this pointer to an object
8061 * \param klass klass of the object containing \p field
8062 * \param field the field to load
8063 * \param res a storage to store the result
8064 * This method is called by the runtime on attempts to load fields of
8065 * transparent proxy objects. \p this points to such TP, \p klass is the class of
8066 * the object containing \p field. \p res is a storage location which can be
8067 * used to store the result.
8068 * \returns an address pointing to the value of field.
8071 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
8074 gpointer result = mono_load_remote_field_checked (this_obj, klass, field, res, &error);
8075 mono_error_cleanup (&error);
8080 * mono_load_remote_field_checked:
8081 * \param this pointer to an object
8082 * \param klass klass of the object containing \p field
8083 * \param field the field to load
8084 * \param res a storage to store the result
8085 * \param error set on error
8086 * This method is called by the runtime on attempts to load fields of
8087 * transparent proxy objects. \p this points to such TP, \p klass is the class of
8088 * the object containing \p field. \p res is a storage location which can be
8089 * used to store the result.
8090 * \returns an address pointing to the value of field. On failure returns NULL and sets \p error.
8093 mono_load_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res, MonoError *error)
8095 MONO_REQ_GC_UNSAFE_MODE;
8097 static MonoMethod *getter = NULL;
8101 MonoDomain *domain = mono_domain_get ();
8102 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8103 MonoClass *field_class;
8104 MonoMethodMessage *msg;
8105 MonoArray *out_args;
8109 g_assert (mono_object_is_transparent_proxy (this_obj));
8110 g_assert (res != NULL);
8112 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8113 mono_field_get_value (tp->rp->unwrapped_server, field, res);
8118 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
8120 mono_error_set_not_supported (error, "Linked away.");
8125 field_class = mono_class_from_mono_type (field->type);
8127 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8128 return_val_if_nok (error, NULL);
8129 out_args = mono_array_new_checked (domain, mono_defaults.object_class, 1, error);
8130 return_val_if_nok (error, NULL);
8131 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, error);
8132 return_val_if_nok (error, NULL);
8133 mono_message_init (domain, msg, rm, out_args, error);
8134 return_val_if_nok (error, NULL);
8136 full_name = mono_type_get_full_name (klass);
8137 MonoString *full_name_str = mono_string_new_checked (domain, full_name, error);
8139 return_val_if_nok (error, NULL);
8140 mono_array_setref (msg->args, 0, full_name_str);
8141 MonoString *field_name = mono_string_new_checked (domain, mono_field_get_name (field), error);
8142 return_val_if_nok (error, NULL);
8143 mono_array_setref (msg->args, 1, field_name);
8145 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8146 return_val_if_nok (error, NULL);
8149 mono_error_set_exception_instance (error, (MonoException *)exc);
8153 if (mono_array_length (out_args) == 0)
8156 mono_gc_wbarrier_generic_store (res, mono_array_get (out_args, MonoObject *, 0));
8158 if (field_class->valuetype) {
8159 return ((char *)*res) + sizeof (MonoObject);
8165 * mono_load_remote_field_new:
8169 * Missing documentation.
8172 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
8176 MonoObject *result = mono_load_remote_field_new_checked (this_obj, klass, field, &error);
8177 mono_error_cleanup (&error);
8182 * mono_load_remote_field_new_checked:
8183 * \param this pointer to an object
8184 * \param klass klass of the object containing \p field
8185 * \param field the field to load
8186 * \param error set on error.
8187 * This method is called by the runtime on attempts to load fields of
8188 * transparent proxy objects. \p this points to such TP, \p klass is the class of
8189 * the object containing \p field.
8190 * \returns a freshly allocated object containing the value of the field. On failure returns NULL and sets \p error.
8193 mono_load_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoError *error)
8195 MONO_REQ_GC_UNSAFE_MODE;
8199 static MonoMethod *tp_load = NULL;
8201 g_assert (mono_object_is_transparent_proxy (this_obj));
8204 tp_load = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "LoadRemoteFieldNew", -1);
8206 mono_error_set_not_supported (error, "Linked away.");
8211 /* MonoType *type = mono_class_get_type (klass); */
8217 return mono_runtime_invoke_checked (tp_load, this_obj, args, error);
8221 * mono_store_remote_field:
8222 * \param this_obj pointer to an object
8223 * \param klass klass of the object containing \p field
8224 * \param field the field to load
8225 * \param val the value/object to store
8226 * This method is called by the runtime on attempts to store fields of
8227 * transparent proxy objects. \p this_obj points to such TP, \p klass is the class of
8228 * the object containing \p field. \p val is the new value to store in \p field.
8231 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
8234 (void) mono_store_remote_field_checked (this_obj, klass, field, val, &error);
8235 mono_error_cleanup (&error);
8239 * mono_store_remote_field_checked:
8240 * \param this_obj pointer to an object
8241 * \param klass klass of the object containing \p field
8242 * \param field the field to load
8243 * \param val the value/object to store
8244 * \param error set on error
8245 * This method is called by the runtime on attempts to store fields of
8246 * transparent proxy objects. \p this_obj points to such TP, \p klass is the class of
8247 * the object containing \p field. \p val is the new value to store in \p field.
8248 * \returns on success returns TRUE, on failure returns FALSE and sets \p error.
8251 mono_store_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val, MonoError *error)
8254 MONO_REQ_GC_UNSAFE_MODE;
8258 MonoDomain *domain = mono_domain_get ();
8259 MonoClass *field_class;
8262 g_assert (mono_object_is_transparent_proxy (this_obj));
8264 field_class = mono_class_from_mono_type (field->type);
8266 if (field_class->valuetype) {
8267 arg = mono_value_box_checked (domain, field_class, val, error);
8268 return_val_if_nok (error, FALSE);
8270 arg = *((MonoObject**)val);
8273 return mono_store_remote_field_new_checked (this_obj, klass, field, arg, error);
8277 * mono_store_remote_field_new:
8282 * Missing documentation
8285 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
8288 (void) mono_store_remote_field_new_checked (this_obj, klass, field, arg, &error);
8289 mono_error_cleanup (&error);
8293 * mono_store_remote_field_new_checked:
8299 * Missing documentation
8302 mono_store_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg, MonoError *error)
8304 MONO_REQ_GC_UNSAFE_MODE;
8306 static MonoMethod *tp_store = NULL;
8310 g_assert (mono_object_is_transparent_proxy (this_obj));
8313 tp_store = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "StoreRemoteField", -1);
8315 mono_error_set_not_supported (error, "Linked away.");
8325 mono_runtime_invoke_checked (tp_store, this_obj, args, error);
8326 return is_ok (error);
8331 * mono_create_ftnptr:
8333 * Given a function address, create a function descriptor for it.
8334 * This is only needed on some platforms.
8337 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
8339 return callbacks.create_ftnptr (domain, addr);
8343 * mono_get_addr_from_ftnptr:
8345 * Given a pointer to a function descriptor, return the function address.
8346 * This is only needed on some platforms.
8349 mono_get_addr_from_ftnptr (gpointer descr)
8351 return callbacks.get_addr_from_ftnptr (descr);
8355 * mono_string_chars:
8356 * \param s a \c MonoString
8357 * \returns a pointer to the UTF-16 characters stored in the \c MonoString
8360 mono_string_chars (MonoString *s)
8362 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
8368 * mono_string_length:
8369 * \param s MonoString
8370 * \returns the length in characters of the string
8373 mono_string_length (MonoString *s)
8375 MONO_REQ_GC_UNSAFE_MODE;
8381 * mono_string_handle_length:
8382 * \param s \c MonoString
8383 * \returns the length in characters of the string
8386 mono_string_handle_length (MonoStringHandle s)
8388 MONO_REQ_GC_UNSAFE_MODE;
8390 return MONO_HANDLE_GETVAL (s, length);
8395 * mono_array_length:
8396 * \param array a \c MonoArray*
8397 * \returns the total number of elements in the array. This works for
8398 * both vectors and multidimensional arrays.
8401 mono_array_length (MonoArray *array)
8403 MONO_REQ_GC_UNSAFE_MODE;
8405 return array->max_length;
8409 * mono_array_addr_with_size:
8410 * \param array a \c MonoArray*
8411 * \param size size of the array elements
8412 * \param idx index into the array
8413 * Use this function to obtain the address for the \p idx item on the
8414 * \p array containing elements of size \p size.
8416 * This method performs no bounds checking or type checking.
8417 * \returns the address of the \p idx element in the array.
8420 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
8422 MONO_REQ_GC_UNSAFE_MODE;
8424 return ((char*)(array)->vector) + size * idx;
8429 mono_glist_to_array (GList *list, MonoClass *eclass, MonoError *error)
8431 MonoDomain *domain = mono_domain_get ();
8439 len = g_list_length (list);
8440 res = mono_array_new_checked (domain, eclass, len, error);
8441 return_val_if_nok (error, NULL);
8443 for (i = 0; list; list = list->next, i++)
8444 mono_array_set (res, gpointer, i, list->data);
8451 * The following section is purely to declare prototypes and
8452 * document the API, as these C files are processed by our
8458 * \param array array to alter
8459 * \param element_type A C type name, this macro will use the sizeof(type) to determine the element size
8460 * \param index index into the array
8461 * \param value value to set
8462 * Value Type version: This sets the \p index's element of the \p array
8463 * with elements of size sizeof(type) to the provided \p value.
8465 * This macro does not attempt to perform type checking or bounds checking.
8467 * Use this to set value types in a \c MonoArray.
8469 void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
8474 * mono_array_setref:
8475 * \param array array to alter
8476 * \param index index into the array
8477 * \param value value to set
8478 * Reference Type version. This sets the \p index's element of the
8479 * \p array with elements of size sizeof(type) to the provided \p value.
8481 * This macro does not attempt to perform type checking or bounds checking.
8483 * Use this to reference types in a \c MonoArray.
8485 void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
8491 * \param array array on which to operate on
8492 * \param element_type C element type (example: \c MonoString*, \c int, \c MonoObject*)
8493 * \param index index into the array
8495 * Use this macro to retrieve the \p index element of an \p array and
8496 * extract the value assuming that the elements of the array match
8497 * the provided type value.
8499 * This method can be used with both arrays holding value types and
8500 * reference types. For reference types, the \p type parameter should
8501 * be a \c MonoObject* or any subclass of it, like \c MonoString*.
8503 * This macro does not attempt to perform type checking or bounds checking.
8505 * \returns The element at the \p index position in the \p array.
8507 Type mono_array_get (MonoArray *array, Type element_type, uintptr_t index)