3 * Object creation for the Mono runtime
6 * Miguel de Icaza (miguel@ximian.com)
7 * Paolo Molaro (lupus@ximian.com)
9 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10 * Copyright 2004-2011 Novell, Inc (http://www.novell.com)
11 * Copyright 2001 Xamarin Inc (http://www.xamarin.com)
12 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
21 #include <mono/metadata/mono-endian.h>
22 #include <mono/metadata/tabledefs.h>
23 #include <mono/metadata/tokentype.h>
24 #include <mono/metadata/loader.h>
25 #include <mono/metadata/object.h>
26 #include <mono/metadata/gc-internals.h>
27 #include <mono/metadata/exception.h>
28 #include <mono/metadata/exception-internals.h>
29 #include <mono/metadata/domain-internals.h>
30 #include "mono/metadata/metadata-internals.h"
31 #include "mono/metadata/class-internals.h"
32 #include <mono/metadata/assembly.h>
33 #include <mono/metadata/marshal.h>
34 #include "mono/metadata/debug-helpers.h"
35 #include <mono/metadata/threads.h>
36 #include <mono/metadata/threads-types.h>
37 #include <mono/metadata/environment.h>
38 #include "mono/metadata/profiler-private.h"
39 #include "mono/metadata/security-manager.h"
40 #include <mono/metadata/verify-internals.h>
41 #include <mono/metadata/reflection-internals.h>
42 #include <mono/metadata/w32event.h>
43 #include <mono/utils/strenc.h>
44 #include <mono/utils/mono-counters.h>
45 #include <mono/utils/mono-error-internals.h>
46 #include <mono/utils/mono-memory-model.h>
47 #include <mono/utils/checked-build.h>
48 #include <mono/utils/mono-threads.h>
49 #include <mono/utils/mono-threads-coop.h>
50 #include "cominterop.h"
51 #include <mono/utils/w32api.h>
54 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error);
57 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error);
60 free_main_args (void);
63 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error);
66 array_full_copy_unchecked_size (MonoArray *src, MonoArray *dest, MonoClass *klass, uintptr_t size);
69 class_get_virtual_method (MonoClass *klass, MonoMethod *method, gboolean is_proxy, MonoError *error);
71 /* Class lazy loading functions */
72 static GENERATE_GET_CLASS_WITH_CACHE (pointer, "System.Reflection", "Pointer")
73 static GENERATE_GET_CLASS_WITH_CACHE (remoting_services, "System.Runtime.Remoting", "RemotingServices")
74 static GENERATE_GET_CLASS_WITH_CACHE (unhandled_exception_event_args, "System", "UnhandledExceptionEventArgs")
75 static GENERATE_GET_CLASS_WITH_CACHE (sta_thread_attribute, "System", "STAThreadAttribute")
76 static GENERATE_GET_CLASS_WITH_CACHE (activation_services, "System.Runtime.Remoting.Activation", "ActivationServices")
79 #define ldstr_lock() mono_os_mutex_lock (&ldstr_section)
80 #define ldstr_unlock() mono_os_mutex_unlock (&ldstr_section)
81 static mono_mutex_t ldstr_section;
85 * mono_runtime_object_init:
86 * \param this_obj the object to initialize
87 * This function calls the zero-argument constructor (which must
88 * exist) for the given object.
91 mono_runtime_object_init (MonoObject *this_obj)
94 mono_runtime_object_init_checked (this_obj, &error);
95 mono_error_assert_ok (&error);
99 * mono_runtime_object_init_checked:
100 * \param this_obj the object to initialize
101 * \param error set on error.
102 * This function calls the zero-argument constructor (which must
103 * exist) for the given object and returns TRUE on success, or FALSE
104 * on error and sets \p error.
107 mono_runtime_object_init_checked (MonoObject *this_obj, MonoError *error)
109 MONO_REQ_GC_UNSAFE_MODE;
111 MonoMethod *method = NULL;
112 MonoClass *klass = this_obj->vtable->klass;
115 method = mono_class_get_method_from_name (klass, ".ctor", 0);
117 g_error ("Could not lookup zero argument constructor for class %s", mono_type_get_full_name (klass));
119 if (method->klass->valuetype)
120 this_obj = (MonoObject *)mono_object_unbox (this_obj);
122 mono_runtime_invoke_checked (method, this_obj, NULL, error);
123 return is_ok (error);
126 /* The pseudo algorithm for type initialization from the spec
127 Note it doesn't say anything about domains - only threads.
129 2. If the type is initialized you are done.
130 2.1. If the type is not yet initialized, try to take an
132 2.2. If successful, record this thread as responsible for
133 initializing the type and proceed to step 2.3.
134 2.2.1. If not, see whether this thread or any thread
135 waiting for this thread to complete already holds the lock.
136 2.2.2. If so, return since blocking would create a deadlock. This thread
137 will now see an incompletely initialized state for the type,
138 but no deadlock will arise.
139 2.2.3 If not, block until the type is initialized then return.
140 2.3 Initialize the parent type and then all interfaces implemented
142 2.4 Execute the type initialization code for this type.
143 2.5 Mark the type as initialized, release the initialization lock,
144 awaken any threads waiting for this type to be initialized,
151 MonoNativeThreadId initializing_tid;
152 guint32 waiting_count;
155 /* condvar used to wait for 'done' becoming TRUE */
157 } TypeInitializationLock;
159 /* for locking access to type_initialization_hash and blocked_thread_hash */
160 static MonoCoopMutex type_initialization_section;
163 mono_type_initialization_lock (void)
165 /* The critical sections protected by this lock in mono_runtime_class_init_full () can block */
166 mono_coop_mutex_lock (&type_initialization_section);
170 mono_type_initialization_unlock (void)
172 mono_coop_mutex_unlock (&type_initialization_section);
176 mono_type_init_lock (TypeInitializationLock *lock)
178 MONO_REQ_GC_NEUTRAL_MODE;
180 mono_coop_mutex_lock (&lock->mutex);
184 mono_type_init_unlock (TypeInitializationLock *lock)
186 mono_coop_mutex_unlock (&lock->mutex);
189 /* from vtable to lock */
190 static GHashTable *type_initialization_hash;
192 /* from thread id to thread id being waited on */
193 static GHashTable *blocked_thread_hash;
196 static MonoThread *main_thread;
198 /* Functions supplied by the runtime */
199 static MonoRuntimeCallbacks callbacks;
202 * mono_thread_set_main:
203 * \param thread thread to set as the main thread
204 * This function can be used to instruct the runtime to treat \p thread
205 * as the main thread, ie, the thread that would normally execute the \c Main
206 * method. This basically means that at the end of \p thread, the runtime will
207 * wait for the existing foreground threads to quit and other such details.
210 mono_thread_set_main (MonoThread *thread)
212 MONO_REQ_GC_UNSAFE_MODE;
214 static gboolean registered = FALSE;
217 MONO_GC_REGISTER_ROOT_SINGLE (main_thread, MONO_ROOT_SOURCE_THREADING, "main thread object");
221 main_thread = thread;
225 * mono_thread_get_main:
228 mono_thread_get_main (void)
230 MONO_REQ_GC_UNSAFE_MODE;
236 mono_type_initialization_init (void)
238 mono_coop_mutex_init_recursive (&type_initialization_section);
239 type_initialization_hash = g_hash_table_new (NULL, NULL);
240 blocked_thread_hash = g_hash_table_new (NULL, NULL);
241 mono_os_mutex_init_recursive (&ldstr_section);
245 mono_type_initialization_cleanup (void)
248 /* This is causing race conditions with
249 * mono_release_type_locks
251 mono_coop_mutex_destroy (&type_initialization_section);
252 g_hash_table_destroy (type_initialization_hash);
253 type_initialization_hash = NULL;
255 mono_os_mutex_destroy (&ldstr_section);
256 g_hash_table_destroy (blocked_thread_hash);
257 blocked_thread_hash = NULL;
263 * get_type_init_exception_for_vtable:
265 * Return the stored type initialization exception for VTABLE.
267 static MonoException*
268 get_type_init_exception_for_vtable (MonoVTable *vtable)
270 MONO_REQ_GC_UNSAFE_MODE;
273 MonoDomain *domain = vtable->domain;
274 MonoClass *klass = vtable->klass;
278 if (!vtable->init_failed)
279 g_error ("Trying to get the init exception for a non-failed vtable of class %s", mono_type_get_full_name (klass));
282 * If the initializing thread was rudely aborted, the exception is not stored
286 mono_domain_lock (domain);
287 if (domain->type_init_exception_hash)
288 ex = (MonoException *)mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
289 mono_domain_unlock (domain);
292 if (klass->name_space && *klass->name_space)
293 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
295 full_name = g_strdup (klass->name);
296 ex = mono_get_exception_type_initialization_checked (full_name, NULL, &error);
298 return_val_if_nok (&error, NULL);
305 * mono_runtime_class_init:
306 * \param vtable vtable that needs to be initialized
307 * This routine calls the class constructor for \p vtable.
310 mono_runtime_class_init (MonoVTable *vtable)
312 MONO_REQ_GC_UNSAFE_MODE;
315 mono_runtime_class_init_full (vtable, &error);
316 mono_error_assert_ok (&error);
320 * Returns TRUE if the lock was freed.
321 * LOCKING: Caller should hold type_initialization_lock.
324 unref_type_lock (TypeInitializationLock *lock)
326 --lock->waiting_count;
327 if (lock->waiting_count == 0) {
328 mono_coop_mutex_destroy (&lock->mutex);
329 mono_coop_cond_destroy (&lock->cond);
338 * mono_runtime_class_init_full:
339 * \param vtable that neeeds to be initialized
340 * \param error set on error
341 * \returns TRUE if class constructor \c .cctor has been initialized successfully, or FALSE otherwise and sets \p error.
344 mono_runtime_class_init_full (MonoVTable *vtable, MonoError *error)
346 MONO_REQ_GC_UNSAFE_MODE;
348 MonoMethod *method = NULL;
351 MonoDomain *domain = vtable->domain;
352 TypeInitializationLock *lock;
353 MonoNativeThreadId tid;
354 int do_initialization = 0;
355 MonoDomain *last_domain = NULL;
356 gboolean pending_tae = FALSE;
360 if (vtable->initialized)
363 klass = vtable->klass;
365 if (!klass->image->checked_module_cctor) {
366 mono_image_check_for_module_cctor (klass->image);
367 if (klass->image->has_module_cctor) {
368 MonoClass *module_klass;
369 MonoVTable *module_vtable;
371 module_klass = mono_class_get_checked (klass->image, MONO_TOKEN_TYPE_DEF | 1, error);
376 module_vtable = mono_class_vtable_full (vtable->domain, module_klass, error);
379 if (!mono_runtime_class_init_full (module_vtable, error))
383 method = mono_class_get_cctor (klass);
385 vtable->initialized = 1;
389 tid = mono_native_thread_id_get ();
392 * Due some preprocessing inside a global lock. If we are the first thread
393 * trying to initialize this class, create a separate lock+cond var, and
394 * acquire it before leaving the global lock. The other threads will wait
398 mono_type_initialization_lock ();
399 /* double check... */
400 if (vtable->initialized) {
401 mono_type_initialization_unlock ();
404 if (vtable->init_failed) {
405 mono_type_initialization_unlock ();
407 /* The type initialization already failed once, rethrow the same exception */
408 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
411 lock = (TypeInitializationLock *)g_hash_table_lookup (type_initialization_hash, vtable);
413 /* This thread will get to do the initialization */
414 if (mono_domain_get () != domain) {
415 /* Transfer into the target domain */
416 last_domain = mono_domain_get ();
417 if (!mono_domain_set (domain, FALSE)) {
418 vtable->initialized = 1;
419 mono_type_initialization_unlock ();
420 mono_error_set_exception_instance (error, mono_get_exception_appdomain_unloaded ());
424 lock = (TypeInitializationLock *)g_malloc0 (sizeof (TypeInitializationLock));
425 mono_coop_mutex_init_recursive (&lock->mutex);
426 mono_coop_cond_init (&lock->cond);
427 lock->initializing_tid = tid;
428 lock->waiting_count = 1;
430 g_hash_table_insert (type_initialization_hash, vtable, lock);
431 do_initialization = 1;
434 TypeInitializationLock *pending_lock;
436 if (mono_native_thread_id_equals (lock->initializing_tid, tid)) {
437 mono_type_initialization_unlock ();
440 /* see if the thread doing the initialization is already blocked on this thread */
441 gboolean is_blocked = TRUE;
442 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (lock->initializing_tid));
443 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
444 if (mono_native_thread_id_equals (pending_lock->initializing_tid, tid)) {
445 if (!pending_lock->done) {
446 mono_type_initialization_unlock ();
449 /* the thread doing the initialization is blocked on this thread,
450 but on a lock that has already been freed. It just hasn't got
456 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (pending_lock->initializing_tid));
458 ++lock->waiting_count;
459 /* record the fact that we are waiting on the initializing thread */
461 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
463 mono_type_initialization_unlock ();
465 if (do_initialization) {
466 MonoException *exc = NULL;
468 /* We are holding the per-vtable lock, do the actual initialization */
470 mono_threads_begin_abort_protected_block ();
471 mono_runtime_try_invoke (method, NULL, NULL, (MonoObject**) &exc, error);
472 mono_threads_end_abort_protected_block ();
474 //exception extracted, error will be set to the right value later
475 if (exc == NULL && !mono_error_ok (error))//invoking failed but exc was not set
476 exc = mono_error_convert_to_exception (error);
478 mono_error_cleanup (error);
482 /* If the initialization failed, mark the class as unusable. */
483 /* Avoid infinite loops */
485 (klass->image == mono_defaults.corlib &&
486 !strcmp (klass->name_space, "System") &&
487 !strcmp (klass->name, "TypeInitializationException")))) {
488 vtable->init_failed = 1;
490 if (klass->name_space && *klass->name_space)
491 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
493 full_name = g_strdup (klass->name);
495 MonoException *exc_to_throw = mono_get_exception_type_initialization_checked (full_name, exc, error);
498 mono_error_assert_ok (error); //We can't recover from this, no way to fail a type we can't alloc a failure.
501 * Store the exception object so it could be thrown on subsequent
504 mono_domain_lock (domain);
505 if (!domain->type_init_exception_hash)
506 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");
507 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
508 mono_domain_unlock (domain);
512 mono_domain_set (last_domain, TRUE);
514 /* Signal to the other threads that we are done */
515 mono_type_init_lock (lock);
517 mono_coop_cond_broadcast (&lock->cond);
518 mono_type_init_unlock (lock);
521 * This can happen if the cctor self-aborts. We need to reactivate tae
522 * (next interruption checkpoint will throw it) and make sure we won't
523 * throw tie for the type.
525 if (exc && mono_object_class (exc) == mono_defaults.threadabortexception_class) {
527 mono_thread_resume_interruption (FALSE);
530 /* this just blocks until the initializing thread is done */
531 mono_type_init_lock (lock);
533 mono_coop_cond_wait (&lock->cond, &lock->mutex);
534 mono_type_init_unlock (lock);
537 /* Do cleanup and setting vtable->initialized inside the global lock again */
538 mono_type_initialization_lock ();
539 if (!do_initialization)
540 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
541 gboolean deleted = unref_type_lock (lock);
543 g_hash_table_remove (type_initialization_hash, vtable);
544 /* Have to set this here since we check it inside the global lock */
545 if (do_initialization && !vtable->init_failed)
546 vtable->initialized = 1;
547 mono_type_initialization_unlock ();
549 /* If vtable init fails because of TAE, we don't throw TIE, only the TAE */
550 if (vtable->init_failed && !pending_tae) {
551 /* Either we were the initializing thread or we waited for the initialization */
552 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
559 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
561 MONO_REQ_GC_NEUTRAL_MODE;
563 MonoVTable *vtable = (MonoVTable*)key;
565 TypeInitializationLock *lock = (TypeInitializationLock*) value;
566 if (mono_native_thread_id_equals (lock->initializing_tid, MONO_UINT_TO_NATIVE_THREAD_ID (GPOINTER_TO_UINT (user))) && !lock->done) {
569 * Have to set this since it cannot be set by the normal code in
570 * mono_runtime_class_init (). In this case, the exception object is not stored,
571 * and get_type_init_exception_for_class () needs to be aware of this.
573 mono_type_init_lock (lock);
574 vtable->init_failed = 1;
575 mono_coop_cond_broadcast (&lock->cond);
576 mono_type_init_unlock (lock);
577 gboolean deleted = unref_type_lock (lock);
585 mono_release_type_locks (MonoInternalThread *thread)
587 MONO_REQ_GC_UNSAFE_MODE;
589 mono_type_initialization_lock ();
590 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, GUINT_TO_POINTER (thread->tid));
591 mono_type_initialization_unlock ();
594 #ifndef DISABLE_REMOTING
597 create_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error)
599 if (!callbacks.create_remoting_trampoline)
600 g_error ("remoting not installed");
601 return callbacks.create_remoting_trampoline (domain, method, target, error);
606 static MonoImtTrampolineBuilder imt_trampoline_builder;
607 static gboolean always_build_imt_trampolines;
609 #if (MONO_IMT_SIZE > 32)
610 #error "MONO_IMT_SIZE cannot be larger than 32"
614 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
616 memcpy (&callbacks, cbs, sizeof (*cbs));
619 MonoRuntimeCallbacks*
620 mono_get_runtime_callbacks (void)
626 mono_install_imt_trampoline_builder (MonoImtTrampolineBuilder func)
628 imt_trampoline_builder = func;
632 mono_set_always_build_imt_trampolines (gboolean value)
634 always_build_imt_trampolines = value;
638 * mono_compile_method:
639 * \param method The method to compile.
640 * This JIT-compiles the method, and returns the pointer to the native code
644 mono_compile_method (MonoMethod *method)
647 gpointer result = mono_compile_method_checked (method, &error);
648 mono_error_cleanup (&error);
653 * mono_compile_method_checked:
654 * \param method The method to compile.
655 * \param error set on error.
656 * This JIT-compiles the method, and returns the pointer to the native code
657 * produced. On failure returns NULL and sets \p error.
660 mono_compile_method_checked (MonoMethod *method, MonoError *error)
664 MONO_REQ_GC_NEUTRAL_MODE
668 g_assert (callbacks.compile_method);
669 res = callbacks.compile_method (method, error);
674 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper, MonoError *error)
678 MONO_REQ_GC_NEUTRAL_MODE;
681 res = callbacks.create_jump_trampoline (domain, method, add_sync_wrapper, error);
686 mono_runtime_create_delegate_trampoline (MonoClass *klass)
688 MONO_REQ_GC_NEUTRAL_MODE
690 g_assert (callbacks.create_delegate_trampoline);
691 return callbacks.create_delegate_trampoline (mono_domain_get (), klass);
695 * mono_runtime_free_method:
696 * \param domain domain where the method is hosted
697 * \param method method to release
698 * This routine is invoked to free the resources associated with
699 * a method that has been JIT compiled. This is used to discard
700 * methods that were used only temporarily (for example, used in marshalling)
703 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
705 MONO_REQ_GC_NEUTRAL_MODE
707 if (callbacks.free_method)
708 callbacks.free_method (domain, method);
710 mono_method_clear_object (domain, method);
712 mono_free_method (method);
716 * The vtables in the root appdomain are assumed to be reachable by other
717 * roots, and we don't use typed allocation in the other domains.
720 /* The sync block is no longer a GC pointer */
721 #define GC_HEADER_BITMAP (0)
723 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
726 compute_class_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
728 MONO_REQ_GC_NEUTRAL_MODE;
730 MonoClassField *field;
736 max_size = mono_class_data_size (klass) / sizeof (gpointer);
738 max_size = klass->instance_size / sizeof (gpointer);
739 if (max_size > size) {
740 g_assert (offset <= 0);
741 bitmap = (gsize *)g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
746 /*An Ephemeron cannot be marked by sgen*/
747 if (!static_fields && klass->image == mono_defaults.corlib && !strcmp ("Ephemeron", klass->name)) {
749 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 static gboolean gcj_inited = FALSE;
1014 MonoGCDescriptor gc_descr;
1017 mono_loader_lock ();
1019 mono_register_jit_icall (ves_icall_object_new_fast, "ves_icall_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
1020 mono_register_jit_icall (ves_icall_string_alloc, "ves_icall_string_alloc", mono_create_icall_signature ("object int"), FALSE);
1023 mono_loader_unlock ();
1027 mono_class_init (klass);
1029 if (klass->gc_descr_inited)
1032 bitmap = default_bitmap;
1033 if (klass == mono_defaults.string_class) {
1034 gc_descr = mono_gc_make_descr_for_string (bitmap, 2);
1035 } else if (klass->rank) {
1036 mono_class_compute_gc_descriptor (klass->element_class);
1037 if (MONO_TYPE_IS_REFERENCE (&klass->element_class->byval_arg)) {
1039 gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
1040 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1041 class->name_space, class->name);*/
1043 /* remove the object header */
1044 bitmap = compute_class_bitmap (klass->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
1045 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));
1046 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1047 class->name_space, class->name);*/
1048 if (bitmap != default_bitmap)
1052 /*static int count = 0;
1055 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1056 gc_descr = mono_gc_make_descr_for_object (bitmap, max_set + 1, klass->instance_size);
1058 if (class->gc_descr == MONO_GC_DESCRIPTOR_NULL)
1059 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
1061 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
1062 if (bitmap != default_bitmap)
1066 /* Publish the data */
1067 mono_loader_lock ();
1068 klass->gc_descr = gc_descr;
1069 mono_memory_barrier ();
1070 klass->gc_descr_inited = TRUE;
1071 mono_loader_unlock ();
1075 * field_is_special_static:
1076 * @fklass: The MonoClass to look up.
1077 * @field: The MonoClassField describing the field.
1079 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1080 * SPECIAL_STATIC_NONE otherwise.
1083 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1085 MONO_REQ_GC_NEUTRAL_MODE;
1088 MonoCustomAttrInfo *ainfo;
1090 ainfo = mono_custom_attrs_from_field_checked (fklass, field, &error);
1091 mono_error_cleanup (&error); /* FIXME don't swallow the error? */
1094 for (i = 0; i < ainfo->num_attrs; ++i) {
1095 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1096 if (klass->image == mono_defaults.corlib) {
1097 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1098 mono_custom_attrs_free (ainfo);
1099 return SPECIAL_STATIC_THREAD;
1101 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1102 mono_custom_attrs_free (ainfo);
1103 return SPECIAL_STATIC_CONTEXT;
1107 mono_custom_attrs_free (ainfo);
1108 return SPECIAL_STATIC_NONE;
1111 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1112 #define mix(a,b,c) { \
1113 a -= c; a ^= rot(c, 4); c += b; \
1114 b -= a; b ^= rot(a, 6); a += c; \
1115 c -= b; c ^= rot(b, 8); b += a; \
1116 a -= c; a ^= rot(c,16); c += b; \
1117 b -= a; b ^= rot(a,19); a += c; \
1118 c -= b; c ^= rot(b, 4); b += a; \
1120 #define final(a,b,c) { \
1121 c ^= b; c -= rot(b,14); \
1122 a ^= c; a -= rot(c,11); \
1123 b ^= a; b -= rot(a,25); \
1124 c ^= b; c -= rot(b,16); \
1125 a ^= c; a -= rot(c,4); \
1126 b ^= a; b -= rot(a,14); \
1127 c ^= b; c -= rot(b,24); \
1131 * mono_method_get_imt_slot:
1133 * The IMT slot is embedded into AOTed code, so this must return the same value
1134 * for the same method across all executions. This means:
1135 * - pointers shouldn't be used as hash values.
1136 * - mono_metadata_str_hash () should be used for hashing strings.
1139 mono_method_get_imt_slot (MonoMethod *method)
1141 MONO_REQ_GC_NEUTRAL_MODE;
1143 MonoMethodSignature *sig;
1145 guint32 *hashes_start, *hashes;
1149 /* This can be used to stress tests the collision code */
1153 * We do this to simplify generic sharing. It will hurt
1154 * performance in cases where a class implements two different
1155 * instantiations of the same generic interface.
1156 * The code in build_imt_slots () depends on this.
1158 if (method->is_inflated)
1159 method = ((MonoMethodInflated*)method)->declaring;
1161 sig = mono_method_signature (method);
1162 hashes_count = sig->param_count + 4;
1163 hashes_start = (guint32 *)malloc (hashes_count * sizeof (guint32));
1164 hashes = hashes_start;
1166 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1167 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1168 method->klass->name_space, method->klass->name, method->name);
1171 /* Initialize hashes */
1172 hashes [0] = mono_metadata_str_hash (method->klass->name);
1173 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1174 hashes [2] = mono_metadata_str_hash (method->name);
1175 hashes [3] = mono_metadata_type_hash (sig->ret);
1176 for (i = 0; i < sig->param_count; i++) {
1177 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1180 /* Setup internal state */
1181 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1183 /* Handle most of the hashes */
1184 while (hashes_count > 3) {
1193 /* Handle the last 3 hashes (all the case statements fall through) */
1194 switch (hashes_count) {
1195 case 3 : c += hashes [2];
1196 case 2 : b += hashes [1];
1197 case 1 : a += hashes [0];
1199 case 0: /* nothing left to add */
1203 g_free (hashes_start);
1204 /* Report the result */
1205 return c % MONO_IMT_SIZE;
1214 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1215 MONO_REQ_GC_NEUTRAL_MODE;
1217 guint32 imt_slot = mono_method_get_imt_slot (method);
1218 MonoImtBuilderEntry *entry;
1220 if (slot_num >= 0 && imt_slot != slot_num) {
1221 /* we build just a single imt slot and this is not it */
1225 entry = (MonoImtBuilderEntry *)g_malloc0 (sizeof (MonoImtBuilderEntry));
1226 entry->key = method;
1227 entry->value.vtable_slot = vtable_slot;
1228 entry->next = imt_builder [imt_slot];
1229 if (imt_builder [imt_slot] != NULL) {
1230 entry->children = imt_builder [imt_slot]->children + 1;
1231 if (entry->children == 1) {
1232 mono_stats.imt_slots_with_collisions++;
1233 *imt_collisions_bitmap |= (1 << imt_slot);
1236 entry->children = 0;
1237 mono_stats.imt_used_slots++;
1239 imt_builder [imt_slot] = entry;
1242 char *method_name = mono_method_full_name (method, TRUE);
1243 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1244 method, method_name, imt_slot, vtable_slot, entry->children);
1245 g_free (method_name);
1252 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1254 MonoMethod *method = e->key;
1255 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1259 method->klass->name_space,
1260 method->klass->name,
1263 printf (" * %s: NULL\n", message);
1269 compare_imt_builder_entries (const void *p1, const void *p2) {
1270 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1271 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1273 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1277 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1279 MONO_REQ_GC_NEUTRAL_MODE;
1281 int count = end - start;
1282 int chunk_start = out_array->len;
1285 for (i = start; i < end; ++i) {
1286 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1287 item->key = sorted_array [i]->key;
1288 item->value = sorted_array [i]->value;
1289 item->has_target_code = sorted_array [i]->has_target_code;
1290 item->is_equals = TRUE;
1292 item->check_target_idx = out_array->len + 1;
1294 item->check_target_idx = 0;
1295 g_ptr_array_add (out_array, item);
1298 int middle = start + count / 2;
1299 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1301 item->key = sorted_array [middle]->key;
1302 item->is_equals = FALSE;
1303 g_ptr_array_add (out_array, item);
1304 imt_emit_ir (sorted_array, start, middle, out_array);
1305 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1311 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1312 MONO_REQ_GC_NEUTRAL_MODE;
1314 int number_of_entries = entries->children + 1;
1315 MonoImtBuilderEntry **sorted_array = (MonoImtBuilderEntry **)malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1316 GPtrArray *result = g_ptr_array_new ();
1317 MonoImtBuilderEntry *current_entry;
1320 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1321 sorted_array [i] = current_entry;
1323 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1325 /*for (i = 0; i < number_of_entries; i++) {
1326 print_imt_entry (" sorted array:", sorted_array [i], i);
1329 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1331 g_free (sorted_array);
1336 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1338 MONO_REQ_GC_NEUTRAL_MODE;
1340 if (imt_builder_entry != NULL) {
1341 if (imt_builder_entry->children == 0 && !fail_tramp && !always_build_imt_trampolines) {
1342 /* No collision, return the vtable slot contents */
1343 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1345 /* Collision, build the trampoline */
1346 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1349 result = imt_trampoline_builder (vtable, domain,
1350 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1351 for (i = 0; i < imt_ir->len; ++i)
1352 g_free (g_ptr_array_index (imt_ir, i));
1353 g_ptr_array_free (imt_ir, TRUE);
1365 static MonoImtBuilderEntry*
1366 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1369 * LOCKING: requires the loader and domain locks.
1373 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1375 MONO_REQ_GC_NEUTRAL_MODE;
1379 guint32 imt_collisions_bitmap = 0;
1380 MonoImtBuilderEntry **imt_builder = (MonoImtBuilderEntry **)calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1381 int method_count = 0;
1382 gboolean record_method_count_for_max_collisions = FALSE;
1383 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1386 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1388 for (i = 0; i < klass->interface_offsets_count; ++i) {
1389 MonoClass *iface = klass->interfaces_packed [i];
1390 int interface_offset = klass->interface_offsets_packed [i];
1391 int method_slot_in_interface, vt_slot;
1393 if (mono_class_has_variant_generic_params (iface))
1394 has_variant_iface = TRUE;
1396 mono_class_setup_methods (iface);
1397 vt_slot = interface_offset;
1398 int mcount = mono_class_get_method_count (iface);
1399 for (method_slot_in_interface = 0; method_slot_in_interface < mcount; method_slot_in_interface++) {
1402 if (slot_num >= 0 && mono_class_is_ginst (iface)) {
1404 * The imt slot of the method is the same as for its declaring method,
1405 * see the comment in mono_method_get_imt_slot (), so we can
1406 * avoid inflating methods which will be discarded by
1407 * add_imt_builder_entry anyway.
1409 method = mono_class_get_method_by_index (mono_class_get_generic_class (iface)->container_class, method_slot_in_interface);
1410 if (mono_method_get_imt_slot (method) != slot_num) {
1415 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1416 if (method->is_generic) {
1417 has_generic_virtual = TRUE;
1422 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1423 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1428 if (extra_interfaces) {
1429 int interface_offset = klass->vtable_size;
1431 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1432 MonoClass* iface = (MonoClass *)list_item->data;
1433 int method_slot_in_interface;
1434 int mcount = mono_class_get_method_count (iface);
1435 for (method_slot_in_interface = 0; method_slot_in_interface < mcount; method_slot_in_interface++) {
1436 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1438 if (method->is_generic)
1439 has_generic_virtual = TRUE;
1440 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1442 interface_offset += mcount;
1445 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1446 /* overwrite the imt slot only if we're building all the entries or if
1447 * we're building this specific one
1449 if (slot_num < 0 || i == slot_num) {
1450 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1453 if (imt_builder [i]) {
1454 MonoImtBuilderEntry *entry;
1456 /* Link entries with imt_builder [i] */
1457 for (entry = entries; entry->next; entry = entry->next) {
1459 MonoMethod *method = (MonoMethod*)entry->key;
1460 char *method_name = mono_method_full_name (method, TRUE);
1461 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1462 g_free (method_name);
1465 entry->next = imt_builder [i];
1466 entries->children += imt_builder [i]->children + 1;
1468 imt_builder [i] = entries;
1471 if (has_generic_virtual || has_variant_iface) {
1473 * There might be collisions later when the the trampoline is expanded.
1475 imt_collisions_bitmap |= (1 << i);
1478 * The IMT trampoline might be called with an instance of one of the
1479 * generic virtual methods, so has to fallback to the IMT trampoline.
1481 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline (vt, i));
1483 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1486 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1490 if (imt_builder [i] != NULL) {
1491 int methods_in_slot = imt_builder [i]->children + 1;
1492 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1493 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1494 record_method_count_for_max_collisions = TRUE;
1496 method_count += methods_in_slot;
1500 mono_stats.imt_number_of_methods += method_count;
1501 if (record_method_count_for_max_collisions) {
1502 mono_stats.imt_method_count_when_max_collisions = method_count;
1505 for (i = 0; i < MONO_IMT_SIZE; i++) {
1506 MonoImtBuilderEntry* entry = imt_builder [i];
1507 while (entry != NULL) {
1508 MonoImtBuilderEntry* next = entry->next;
1513 g_free (imt_builder);
1514 /* we OR the bitmap since we may build just a single imt slot at a time */
1515 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1519 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1520 MONO_REQ_GC_NEUTRAL_MODE;
1522 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1526 * mono_vtable_build_imt_slot:
1527 * \param vtable virtual object table struct
1528 * \param imt_slot slot in the IMT table
1529 * Fill the given \p imt_slot in the IMT table of \p vtable with
1530 * a trampoline or a trampoline for the case of collisions.
1531 * This is part of the internal mono API.
1532 * LOCKING: Take the domain lock.
1535 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1537 MONO_REQ_GC_NEUTRAL_MODE;
1539 gpointer *imt = (gpointer*)vtable;
1540 imt -= MONO_IMT_SIZE;
1541 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1543 /* no support for extra interfaces: the proxy objects will need
1544 * to build the complete IMT
1545 * Update and heck needs to ahppen inside the proper domain lock, as all
1546 * the changes made to a MonoVTable.
1548 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1549 mono_domain_lock (vtable->domain);
1550 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1551 if (!callbacks.imt_entry_inited (vtable, imt_slot))
1552 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1553 mono_domain_unlock (vtable->domain);
1554 mono_loader_unlock ();
1557 #define THUNK_THRESHOLD 10
1560 * mono_method_alloc_generic_virtual_trampoline:
1561 * \param domain a domain
1562 * \param size size in bytes
1563 * Allocs \p size bytes to be used for the code of a generic virtual
1564 * trampoline. It's either allocated from the domain's code manager or
1565 * reused from a previously invalidated piece.
1566 * LOCKING: The domain lock must be held.
1569 mono_method_alloc_generic_virtual_trampoline (MonoDomain *domain, int size)
1571 MONO_REQ_GC_NEUTRAL_MODE;
1573 static gboolean inited = FALSE;
1574 static int generic_virtual_trampolines_size = 0;
1577 mono_counters_register ("Generic virtual trampoline bytes",
1578 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_trampolines_size);
1581 generic_virtual_trampolines_size += size;
1583 return mono_domain_code_reserve (domain, size);
1586 typedef struct _GenericVirtualCase {
1590 struct _GenericVirtualCase *next;
1591 } GenericVirtualCase;
1594 * get_generic_virtual_entries:
1596 * Return IMT entries for the generic virtual method instances and
1597 * variant interface methods for vtable slot
1600 static MonoImtBuilderEntry*
1601 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1603 MONO_REQ_GC_NEUTRAL_MODE;
1605 GenericVirtualCase *list;
1606 MonoImtBuilderEntry *entries;
1608 mono_domain_lock (domain);
1609 if (!domain->generic_virtual_cases)
1610 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1612 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1615 for (; list; list = list->next) {
1616 MonoImtBuilderEntry *entry;
1618 if (list->count < THUNK_THRESHOLD)
1621 entry = g_new0 (MonoImtBuilderEntry, 1);
1622 entry->key = list->method;
1623 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1624 entry->has_target_code = 1;
1626 entry->children = entries->children + 1;
1627 entry->next = entries;
1631 mono_domain_unlock (domain);
1633 /* FIXME: Leaking memory ? */
1638 * \param domain a domain
1639 * \param vtable_slot pointer to the vtable slot
1640 * \param method the inflated generic virtual method
1641 * \param code the method's code
1643 * Registers a call via unmanaged code to a generic virtual method
1644 * instantiation or variant interface method. If the number of calls reaches a threshold
1645 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1646 * virtual method trampoline.
1649 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1650 gpointer *vtable_slot,
1651 MonoMethod *method, gpointer code)
1653 MONO_REQ_GC_NEUTRAL_MODE;
1655 static gboolean inited = FALSE;
1656 static int num_added = 0;
1657 static int num_freed = 0;
1659 GenericVirtualCase *gvc, *list;
1660 MonoImtBuilderEntry *entries;
1664 mono_domain_lock (domain);
1665 if (!domain->generic_virtual_cases)
1666 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1669 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1670 mono_counters_register ("Freed IMT trampolines", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_freed);
1674 /* Check whether the case was already added */
1675 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1678 if (gvc->method == method)
1683 /* If not found, make a new one */
1685 gvc = (GenericVirtualCase *)mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1686 gvc->method = method;
1689 gvc->next = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1691 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1696 if (++gvc->count == THUNK_THRESHOLD) {
1697 gpointer *old_thunk = (void **)*vtable_slot;
1698 gpointer vtable_trampoline = NULL;
1699 gpointer imt_trampoline = NULL;
1701 if ((gpointer)vtable_slot < (gpointer)vtable) {
1702 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1703 int imt_slot = MONO_IMT_SIZE + displacement;
1705 /* Force the rebuild of the trampoline at the next call */
1706 imt_trampoline = callbacks.get_imt_trampoline (vtable, imt_slot);
1707 *vtable_slot = imt_trampoline;
1709 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline (vtable, (gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1711 entries = get_generic_virtual_entries (domain, vtable_slot);
1713 sorted = imt_sort_slot_entries (entries);
1715 *vtable_slot = imt_trampoline_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1719 MonoImtBuilderEntry *next = entries->next;
1724 for (i = 0; i < sorted->len; ++i)
1725 g_free (g_ptr_array_index (sorted, i));
1726 g_ptr_array_free (sorted, TRUE);
1728 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1733 mono_domain_unlock (domain);
1736 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error);
1739 * mono_class_vtable:
1740 * \param domain the application domain
1741 * \param class the class to initialize
1742 * VTables are domain specific because we create domain specific code, and
1743 * they contain the domain specific static class data.
1744 * On failure, NULL is returned, and \c class->exception_type is set.
1747 mono_class_vtable (MonoDomain *domain, MonoClass *klass)
1750 MonoVTable* vtable = mono_class_vtable_full (domain, klass, &error);
1751 mono_error_cleanup (&error);
1756 * mono_class_vtable_full:
1757 * \param domain the application domain
1758 * \param class the class to initialize
1759 * \param error set on failure.
1760 * VTables are domain specific because we create domain specific code, and
1761 * they contain the domain specific static class data.
1764 mono_class_vtable_full (MonoDomain *domain, MonoClass *klass, MonoError *error)
1766 MONO_REQ_GC_UNSAFE_MODE;
1768 MonoClassRuntimeInfo *runtime_info;
1774 if (mono_class_has_failure (klass)) {
1775 mono_error_set_for_class_failure (error, klass);
1779 /* this check can be inlined in jitted code, too */
1780 runtime_info = klass->runtime_info;
1781 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1782 return runtime_info->domain_vtables [domain->domain_id];
1783 return mono_class_create_runtime_vtable (domain, klass, error);
1787 * mono_class_try_get_vtable:
1788 * \param domain the application domain
1789 * \param class the class to initialize
1790 * This function tries to get the associated vtable from \p class if
1791 * it was already created.
1794 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *klass)
1796 MONO_REQ_GC_NEUTRAL_MODE;
1798 MonoClassRuntimeInfo *runtime_info;
1802 runtime_info = klass->runtime_info;
1803 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1804 return runtime_info->domain_vtables [domain->domain_id];
1809 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1811 MONO_REQ_GC_NEUTRAL_MODE;
1813 size_t alloc_offset;
1816 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1817 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1818 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1820 if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1821 g_assert ((imt_table_bytes & 7) == 4);
1828 return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1832 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error)
1834 MONO_REQ_GC_UNSAFE_MODE;
1837 MonoClassRuntimeInfo *runtime_info, *old_info;
1838 MonoClassField *field;
1840 int i, vtable_slots;
1841 size_t imt_table_bytes;
1843 guint32 vtable_size, class_size;
1845 gpointer *interface_offsets;
1849 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1850 mono_domain_lock (domain);
1851 runtime_info = klass->runtime_info;
1852 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1853 mono_domain_unlock (domain);
1854 mono_loader_unlock ();
1855 return runtime_info->domain_vtables [domain->domain_id];
1857 if (!klass->inited || mono_class_has_failure (klass)) {
1858 if (!mono_class_init (klass) || mono_class_has_failure (klass)) {
1859 mono_domain_unlock (domain);
1860 mono_loader_unlock ();
1861 mono_error_set_for_class_failure (error, klass);
1866 /* Array types require that their element type be valid*/
1867 if (klass->byval_arg.type == MONO_TYPE_ARRAY || klass->byval_arg.type == MONO_TYPE_SZARRAY) {
1868 MonoClass *element_class = klass->element_class;
1869 if (!element_class->inited)
1870 mono_class_init (element_class);
1872 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1873 if (!mono_class_has_failure (element_class) && !element_class->vtable_size)
1874 mono_class_setup_vtable (element_class);
1876 if (mono_class_has_failure (element_class)) {
1877 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1878 if (!mono_class_has_failure (klass))
1879 mono_class_set_type_load_failure (klass, "");
1880 mono_domain_unlock (domain);
1881 mono_loader_unlock ();
1882 mono_error_set_for_class_failure (error, klass);
1888 * For some classes, mono_class_init () already computed klass->vtable_size, and
1889 * that is all that is needed because of the vtable trampolines.
1891 if (!klass->vtable_size)
1892 mono_class_setup_vtable (klass);
1894 if (mono_class_is_ginst (klass) && !klass->vtable)
1895 mono_class_check_vtable_constraints (klass, NULL);
1897 /* Initialize klass->has_finalize */
1898 mono_class_has_finalizer (klass);
1900 if (mono_class_has_failure (klass)) {
1901 mono_domain_unlock (domain);
1902 mono_loader_unlock ();
1903 mono_error_set_for_class_failure (error, klass);
1907 vtable_slots = klass->vtable_size;
1908 /* we add an additional vtable slot to store the pointer to static field data only when needed */
1909 class_size = mono_class_data_size (klass);
1913 if (klass->interface_offsets_count) {
1914 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1915 mono_stats.imt_number_of_tables++;
1916 mono_stats.imt_tables_size += imt_table_bytes;
1918 imt_table_bytes = 0;
1921 vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
1923 mono_stats.used_class_count++;
1924 mono_stats.class_vtable_size += vtable_size;
1926 interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
1927 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1928 g_assert (!((gsize)vt & 7));
1931 vt->rank = klass->rank;
1932 vt->domain = domain;
1934 mono_class_compute_gc_descriptor (klass);
1936 * We can't use typed allocation in the non-root domains, since the
1937 * collector needs the GC descriptor stored in the vtable even after
1938 * the mempool containing the vtable is destroyed when the domain is
1939 * unloaded. An alternative might be to allocate vtables in the GC
1940 * heap, but this does not seem to work (it leads to crashes inside
1941 * libgc). If that approach is tried, two gc descriptors need to be
1942 * allocated for each class: one for the root domain, and one for all
1943 * other domains. The second descriptor should contain a bit for the
1944 * vtable field in MonoObject, since we can no longer assume the
1945 * vtable is reachable by other roots after the appdomain is unloaded.
1947 #ifdef HAVE_BOEHM_GC
1948 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1949 vt->gc_descr = MONO_GC_DESCRIPTOR_NULL;
1952 vt->gc_descr = klass->gc_descr;
1954 gc_bits = mono_gc_get_vtable_bits (klass);
1955 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
1957 vt->gc_bits = gc_bits;
1960 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
1961 if (klass->has_static_refs) {
1962 MonoGCDescriptor statics_gc_descr;
1964 gsize default_bitmap [4] = {0};
1967 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1968 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], klass->name_space, klass->name, class_size);*/
1969 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1970 vt->vtable [klass->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr, MONO_ROOT_SOURCE_STATIC, "managed static variables");
1971 if (bitmap != default_bitmap)
1974 vt->vtable [klass->vtable_size] = mono_domain_alloc0 (domain, class_size);
1976 vt->has_static_fields = TRUE;
1977 mono_stats.class_static_data_size += class_size;
1981 while ((field = mono_class_get_fields (klass, &iter))) {
1982 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1984 if (mono_field_is_deleted (field))
1986 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1987 gint32 special_static = klass->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (klass, field);
1988 if (special_static != SPECIAL_STATIC_NONE) {
1989 guint32 size, offset;
1991 gsize default_bitmap [4] = {0};
1996 if (mono_type_is_reference (field->type)) {
1997 default_bitmap [0] = 1;
1999 bitmap = default_bitmap;
2000 } else if (mono_type_is_struct (field->type)) {
2001 fclass = mono_class_from_mono_type (field->type);
2002 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
2003 numbits = max_set + 1;
2005 default_bitmap [0] = 0;
2007 bitmap = default_bitmap;
2009 size = mono_type_size (field->type, &align);
2010 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
2011 if (!domain->special_static_fields)
2012 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2013 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2014 if (bitmap != default_bitmap)
2017 * This marks the field as special static to speed up the
2018 * checks in mono_field_static_get/set_value ().
2024 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2025 MonoClass *fklass = mono_class_from_mono_type (field->type);
2026 const char *data = mono_field_get_data (field);
2028 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2029 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2030 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2033 if (fklass->valuetype) {
2034 memcpy (t, data, mono_class_value_size (fklass, NULL));
2036 /* it's a pointer type: add check */
2037 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2044 vt->max_interface_id = klass->max_interface_id;
2045 vt->interface_bitmap = klass->interface_bitmap;
2047 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2048 // class->name, klass->interface_offsets_count);
2050 /* Initialize vtable */
2051 if (callbacks.get_vtable_trampoline) {
2052 // This also covers the AOT case
2053 for (i = 0; i < klass->vtable_size; ++i) {
2054 vt->vtable [i] = callbacks.get_vtable_trampoline (vt, i);
2057 mono_class_setup_vtable (klass);
2059 for (i = 0; i < klass->vtable_size; ++i) {
2062 cm = klass->vtable [i];
2064 vt->vtable [i] = callbacks.create_jit_trampoline (domain, cm, error);
2065 if (!is_ok (error)) {
2066 mono_domain_unlock (domain);
2067 mono_loader_unlock ();
2074 if (imt_table_bytes) {
2075 /* Now that the vtable is full, we can actually fill up the IMT */
2076 for (i = 0; i < MONO_IMT_SIZE; ++i)
2077 interface_offsets [i] = callbacks.get_imt_trampoline (vt, i);
2081 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2082 * re-acquire them and check if another thread has created the vtable in the meantime.
2084 /* Special case System.MonoType to avoid infinite recursion */
2085 if (klass != mono_defaults.runtimetype_class) {
2086 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2087 if (!is_ok (error)) {
2088 mono_domain_unlock (domain);
2089 mono_loader_unlock ();
2093 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2094 /* This is unregistered in
2095 unregister_vtable_reflection_type() in
2097 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2100 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (klass));
2102 /* class_vtable_array keeps an array of created vtables
2104 g_ptr_array_add (domain->class_vtable_array, vt);
2105 /* klass->runtime_info is protected by the loader lock, both when
2106 * it it enlarged and when it is stored info.
2110 * Store the vtable in klass->runtime_info.
2111 * klass->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2113 mono_memory_barrier ();
2115 old_info = klass->runtime_info;
2116 if (old_info && old_info->max_domain >= domain->domain_id) {
2117 /* someone already created a large enough runtime info */
2118 old_info->domain_vtables [domain->domain_id] = vt;
2120 int new_size = domain->domain_id;
2122 new_size = MAX (new_size, old_info->max_domain);
2124 /* make the new size a power of two */
2126 while (new_size > i)
2129 /* this is a bounded memory retention issue: may want to
2130 * handle it differently when we'll have a rcu-like system.
2132 runtime_info = (MonoClassRuntimeInfo *)mono_image_alloc0 (klass->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2133 runtime_info->max_domain = new_size - 1;
2134 /* copy the stuff from the older info */
2136 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2138 runtime_info->domain_vtables [domain->domain_id] = vt;
2140 mono_memory_barrier ();
2141 klass->runtime_info = runtime_info;
2144 if (klass == mono_defaults.runtimetype_class) {
2145 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2146 if (!is_ok (error)) {
2147 mono_domain_unlock (domain);
2148 mono_loader_unlock ();
2152 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2153 /* This is unregistered in
2154 unregister_vtable_reflection_type() in
2156 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2159 mono_domain_unlock (domain);
2160 mono_loader_unlock ();
2162 /* make sure the parent is initialized */
2163 /*FIXME shouldn't this fail the current type?*/
2165 mono_class_vtable_full (domain, klass->parent, error);
2170 #ifndef DISABLE_REMOTING
2172 * mono_class_proxy_vtable:
2173 * \param domain the application domain
2174 * \param remove_class the remote class
2175 * \param error set on error
2176 * Creates a vtable for transparent proxies. It is basically
2177 * a copy of the real vtable of the class wrapped in \p remote_class,
2178 * but all function pointers invoke the remoting functions, and
2179 * \c vtable->klass points to the transparent proxy class, and not to \p class.
2181 * On failure returns NULL and sets \p error
2184 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type, MonoError *error)
2186 MONO_REQ_GC_UNSAFE_MODE;
2188 MonoVTable *vt, *pvt;
2189 int i, j, vtsize, extra_interface_vtsize = 0;
2190 guint32 max_interface_id;
2192 GSList *extra_interfaces = NULL;
2193 MonoClass *klass = remote_class->proxy_class;
2194 gpointer *interface_offsets;
2195 uint8_t *bitmap = NULL;
2197 size_t imt_table_bytes;
2199 #ifdef COMPRESSED_INTERFACE_BITMAP
2205 vt = mono_class_vtable (domain, klass);
2206 g_assert (vt); /*FIXME property handle failure*/
2207 max_interface_id = vt->max_interface_id;
2209 /* Calculate vtable space for extra interfaces */
2210 for (j = 0; j < remote_class->interface_count; j++) {
2211 MonoClass* iclass = remote_class->interfaces[j];
2215 /*FIXME test for interfaces with variant generic arguments*/
2216 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, iclass->interface_id))
2217 continue; /* interface implemented by the class */
2218 if (g_slist_find (extra_interfaces, iclass))
2221 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2223 method_count = mono_class_num_methods (iclass);
2225 ifaces = mono_class_get_implemented_interfaces (iclass, error);
2229 for (i = 0; i < ifaces->len; ++i) {
2230 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2231 /*FIXME test for interfaces with variant generic arguments*/
2232 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, ic->interface_id))
2233 continue; /* interface implemented by the class */
2234 if (g_slist_find (extra_interfaces, ic))
2236 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2237 method_count += mono_class_num_methods (ic);
2239 g_ptr_array_free (ifaces, TRUE);
2243 extra_interface_vtsize += method_count * sizeof (gpointer);
2244 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2247 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2248 mono_stats.imt_number_of_tables++;
2249 mono_stats.imt_tables_size += imt_table_bytes;
2251 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer);
2253 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2255 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2256 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2257 g_assert (!((gsize)pvt & 7));
2259 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer));
2261 pvt->klass = mono_defaults.transparent_proxy_class;
2262 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2263 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2265 /* initialize vtable */
2266 mono_class_setup_vtable (klass);
2267 for (i = 0; i < klass->vtable_size; ++i) {
2270 if ((cm = klass->vtable [i])) {
2271 pvt->vtable [i] = create_remoting_trampoline (domain, cm, target_type, error);
2275 pvt->vtable [i] = NULL;
2278 if (mono_class_is_abstract (klass)) {
2279 /* create trampolines for abstract methods */
2280 for (k = klass; k; k = k->parent) {
2282 gpointer iter = NULL;
2283 while ((m = mono_class_get_methods (k, &iter)))
2284 if (!pvt->vtable [m->slot]) {
2285 pvt->vtable [m->slot] = create_remoting_trampoline (domain, m, target_type, error);
2292 pvt->max_interface_id = max_interface_id;
2293 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2294 #ifdef COMPRESSED_INTERFACE_BITMAP
2295 bitmap = (uint8_t *)g_malloc0 (bsize);
2297 bitmap = (uint8_t *)mono_domain_alloc0 (domain, bsize);
2300 for (i = 0; i < klass->interface_offsets_count; ++i) {
2301 int interface_id = klass->interfaces_packed [i]->interface_id;
2302 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2305 if (extra_interfaces) {
2306 int slot = klass->vtable_size;
2312 /* Create trampolines for the methods of the interfaces */
2313 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2314 interf = (MonoClass *)list_item->data;
2316 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2320 while ((cm = mono_class_get_methods (interf, &iter))) {
2321 pvt->vtable [slot + j++] = create_remoting_trampoline (domain, cm, target_type, error);
2326 slot += mono_class_num_methods (interf);
2330 /* Now that the vtable is full, we can actually fill up the IMT */
2331 build_imt (klass, pvt, domain, interface_offsets, extra_interfaces);
2332 if (extra_interfaces) {
2333 g_slist_free (extra_interfaces);
2336 #ifdef COMPRESSED_INTERFACE_BITMAP
2337 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2338 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2339 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2342 pvt->interface_bitmap = bitmap;
2346 if (extra_interfaces)
2347 g_slist_free (extra_interfaces);
2348 #ifdef COMPRESSED_INTERFACE_BITMAP
2354 #endif /* DISABLE_REMOTING */
2357 * mono_class_field_is_special_static:
2358 * \returns whether \p field is a thread/context static field.
2361 mono_class_field_is_special_static (MonoClassField *field)
2363 MONO_REQ_GC_NEUTRAL_MODE
2365 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2367 if (mono_field_is_deleted (field))
2369 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2370 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2377 * mono_class_field_get_special_static_type:
2378 * \param field The \c MonoClassField describing the field.
2379 * \returns \c SPECIAL_STATIC_THREAD if the field is thread static, \c SPECIAL_STATIC_CONTEXT if it is context static,
2380 * \c SPECIAL_STATIC_NONE otherwise.
2383 mono_class_field_get_special_static_type (MonoClassField *field)
2385 MONO_REQ_GC_NEUTRAL_MODE
2387 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2388 return SPECIAL_STATIC_NONE;
2389 if (mono_field_is_deleted (field))
2390 return SPECIAL_STATIC_NONE;
2391 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2392 return field_is_special_static (field->parent, field);
2393 return SPECIAL_STATIC_NONE;
2397 * mono_class_has_special_static_fields:
2398 * \returns whether \p klass has any thread/context static fields.
2401 mono_class_has_special_static_fields (MonoClass *klass)
2403 MONO_REQ_GC_NEUTRAL_MODE
2405 MonoClassField *field;
2409 while ((field = mono_class_get_fields (klass, &iter))) {
2410 g_assert (field->parent == klass);
2411 if (mono_class_field_is_special_static (field))
2418 #ifndef DISABLE_REMOTING
2420 * create_remote_class_key:
2421 * Creates an array of pointers that can be used as a hash key for a remote class.
2422 * The first element of the array is the number of pointers.
2425 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2427 MONO_REQ_GC_NEUTRAL_MODE;
2432 if (remote_class == NULL) {
2433 if (mono_class_is_interface (extra_class)) {
2434 key = (void **)g_malloc (sizeof(gpointer) * 3);
2435 key [0] = GINT_TO_POINTER (2);
2436 key [1] = mono_defaults.marshalbyrefobject_class;
2437 key [2] = extra_class;
2439 key = (void **)g_malloc (sizeof(gpointer) * 2);
2440 key [0] = GINT_TO_POINTER (1);
2441 key [1] = extra_class;
2444 if (extra_class != NULL && mono_class_is_interface (extra_class)) {
2445 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2446 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2447 key [1] = remote_class->proxy_class;
2449 // Keep the list of interfaces sorted
2450 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2451 if (extra_class && remote_class->interfaces [i] > extra_class) {
2452 key [j++] = extra_class;
2455 key [j] = remote_class->interfaces [i];
2458 key [j] = extra_class;
2460 // Replace the old class. The interface list is the same
2461 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2462 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2463 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2464 for (i = 0; i < remote_class->interface_count; i++)
2465 key [2 + i] = remote_class->interfaces [i];
2473 * copy_remote_class_key:
2475 * Make a copy of KEY in the domain and return the copy.
2478 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2480 MONO_REQ_GC_NEUTRAL_MODE
2482 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2483 gpointer *mp_key = (gpointer *)mono_domain_alloc (domain, key_size);
2485 memcpy (mp_key, key, key_size);
2491 * mono_remote_class:
2492 * \param domain the application domain
2493 * \param class_name name of the remote class
2494 * \param error set on error
2495 * Creates and initializes a \c MonoRemoteClass object for a remote type.
2496 * On failure returns NULL and sets \p error
2499 mono_remote_class (MonoDomain *domain, MonoStringHandle class_name, MonoClass *proxy_class, MonoError *error)
2501 MONO_REQ_GC_UNSAFE_MODE;
2503 MonoRemoteClass *rc;
2504 gpointer* key, *mp_key;
2509 key = create_remote_class_key (NULL, proxy_class);
2511 mono_domain_lock (domain);
2512 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2516 mono_domain_unlock (domain);
2520 name = mono_string_to_utf8_mp (domain->mp, MONO_HANDLE_RAW (class_name), error);
2521 if (!is_ok (error)) {
2523 mono_domain_unlock (domain);
2527 mp_key = copy_remote_class_key (domain, key);
2531 if (mono_class_is_interface (proxy_class)) {
2532 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2533 rc->interface_count = 1;
2534 rc->interfaces [0] = proxy_class;
2535 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2537 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2538 rc->interface_count = 0;
2539 rc->proxy_class = proxy_class;
2542 rc->default_vtable = NULL;
2543 rc->xdomain_vtable = NULL;
2544 rc->proxy_class_name = name;
2545 #ifndef DISABLE_PERFCOUNTERS
2546 mono_perfcounters->loader_bytes += mono_string_length (MONO_HANDLE_RAW (class_name)) + 1;
2549 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2551 mono_domain_unlock (domain);
2556 * clone_remote_class:
2557 * Creates a copy of the remote_class, adding the provided class or interface
2559 static MonoRemoteClass*
2560 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2562 MONO_REQ_GC_NEUTRAL_MODE;
2564 MonoRemoteClass *rc;
2565 gpointer* key, *mp_key;
2567 key = create_remote_class_key (remote_class, extra_class);
2568 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2574 mp_key = copy_remote_class_key (domain, key);
2578 if (mono_class_is_interface (extra_class)) {
2580 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2581 rc->proxy_class = remote_class->proxy_class;
2582 rc->interface_count = remote_class->interface_count + 1;
2584 // Keep the list of interfaces sorted, since the hash key of
2585 // the remote class depends on this
2586 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2587 if (remote_class->interfaces [i] > extra_class && i == j)
2588 rc->interfaces [j++] = extra_class;
2589 rc->interfaces [j] = remote_class->interfaces [i];
2592 rc->interfaces [j] = extra_class;
2594 // Replace the old class. The interface array is the same
2595 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2596 rc->proxy_class = extra_class;
2597 rc->interface_count = remote_class->interface_count;
2598 if (rc->interface_count > 0)
2599 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2602 rc->default_vtable = NULL;
2603 rc->xdomain_vtable = NULL;
2604 rc->proxy_class_name = remote_class->proxy_class_name;
2606 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2612 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxyHandle rp, MonoError *error)
2614 MONO_REQ_GC_UNSAFE_MODE;
2618 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2619 mono_domain_lock (domain);
2620 gint32 target_domain_id = MONO_HANDLE_GETVAL (rp, target_domain_id);
2621 if (target_domain_id != -1) {
2622 if (remote_class->xdomain_vtable == NULL)
2623 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN, error);
2624 mono_domain_unlock (domain);
2625 mono_loader_unlock ();
2626 return_val_if_nok (error, NULL);
2627 return remote_class->xdomain_vtable;
2629 if (remote_class->default_vtable == NULL) {
2630 MonoReflectionTypeHandle reftype = MONO_HANDLE_NEW (MonoReflectionType, NULL);
2631 MONO_HANDLE_GET (reftype, rp, class_to_proxy);
2633 MonoType *type = MONO_HANDLE_GETVAL (reftype, type);
2634 MonoClass *klass = mono_class_from_mono_type (type);
2636 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)))
2637 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP, error);
2640 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN, error);
2641 /* N.B. both branches of the if modify error */
2642 if (!is_ok (error)) {
2643 mono_domain_unlock (domain);
2644 mono_loader_unlock ();
2649 mono_domain_unlock (domain);
2650 mono_loader_unlock ();
2651 return remote_class->default_vtable;
2655 * mono_upgrade_remote_class:
2656 * \param domain the application domain
2657 * \param tproxy the proxy whose remote class has to be upgraded.
2658 * \param klass class to which the remote class can be casted.
2659 * \param error set on error
2660 * Updates the vtable of the remote class by adding the necessary method slots
2661 * and interface offsets so it can be safely casted to klass. klass can be a
2662 * class or an interface. On success returns TRUE, on failure returns FALSE and sets \p error.
2665 mono_upgrade_remote_class (MonoDomain *domain, MonoObjectHandle proxy_object, MonoClass *klass, MonoError *error)
2667 MONO_REQ_GC_UNSAFE_MODE;
2671 MonoTransparentProxyHandle tproxy = MONO_HANDLE_CAST (MonoTransparentProxy, proxy_object);
2672 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (tproxy, remote_class);
2674 gboolean redo_vtable;
2675 if (mono_class_is_interface (klass)) {
2678 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2679 if (remote_class->interfaces [i] == klass)
2680 redo_vtable = FALSE;
2683 redo_vtable = (remote_class->proxy_class != klass);
2686 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2687 mono_domain_lock (domain);
2689 MonoRemoteClass *fresh_remote_class = clone_remote_class (domain, remote_class, klass);
2690 MONO_HANDLE_SETVAL (tproxy, remote_class, MonoRemoteClass*, fresh_remote_class);
2691 MonoRealProxyHandle real_proxy = MONO_HANDLE_NEW (MonoRealProxy, NULL);
2692 MONO_HANDLE_GET (real_proxy, tproxy, rp);
2693 MONO_HANDLE_SETVAL (proxy_object, vtable, MonoVTable*, mono_remote_class_vtable (domain, fresh_remote_class, real_proxy, error));
2699 mono_domain_unlock (domain);
2700 mono_loader_unlock ();
2701 return is_ok (error);
2703 #endif /* DISABLE_REMOTING */
2707 * mono_object_get_virtual_method:
2708 * \param obj object to operate on.
2709 * \param method method
2710 * Retrieves the \c MonoMethod that would be called on \p obj if \p obj is passed as
2711 * the instance of a callvirt of \p method.
2714 mono_object_get_virtual_method (MonoObject *obj_raw, MonoMethod *method)
2716 MONO_REQ_GC_UNSAFE_MODE;
2717 HANDLE_FUNCTION_ENTER ();
2719 MONO_HANDLE_DCL (MonoObject, obj);
2720 MonoMethod *result = mono_object_handle_get_virtual_method (obj, method, &error);
2721 mono_error_assert_ok (&error);
2722 HANDLE_FUNCTION_RETURN_VAL (result);
2726 * mono_object_handle_get_virtual_method:
2727 * \param obj object to operate on.
2728 * \param method method
2729 * Retrieves the \c MonoMethod that would be called on \p obj if \p obj is passed as
2730 * the instance of a callvirt of \p method.
2733 mono_object_handle_get_virtual_method (MonoObjectHandle obj, MonoMethod *method, MonoError *error)
2737 gboolean is_proxy = FALSE;
2738 MonoClass *klass = mono_handle_class (obj);
2739 if (mono_class_is_transparent_proxy (klass)) {
2740 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), remote_class);
2741 klass = remote_class->proxy_class;
2744 return class_get_virtual_method (klass, method, is_proxy, error);
2748 class_get_virtual_method (MonoClass *klass, MonoMethod *method, gboolean is_proxy, MonoError *error)
2753 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2756 mono_class_setup_vtable (klass);
2757 MonoMethod **vtable = klass->vtable;
2759 if (method->slot == -1) {
2760 /* method->slot might not be set for instances of generic methods */
2761 if (method->is_inflated) {
2762 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2763 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2766 g_assert_not_reached ();
2770 MonoMethod *res = NULL;
2771 /* check method->slot is a valid index: perform isinstance? */
2772 if (method->slot != -1) {
2773 if (mono_class_is_interface (method->klass)) {
2775 gboolean variance_used = FALSE;
2776 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2777 g_assert (iface_offset > 0);
2778 res = vtable [iface_offset + method->slot];
2781 res = vtable [method->slot];
2785 #ifndef DISABLE_REMOTING
2787 /* It may be an interface, abstract class method or generic method */
2788 if (!res || mono_method_signature (res)->generic_param_count)
2791 /* generic methods demand invoke_with_check */
2792 if (mono_method_signature (res)->generic_param_count)
2793 res = mono_marshal_get_remoting_invoke_with_check (res);
2796 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2797 res = mono_cominterop_get_invoke (res);
2800 res = mono_marshal_get_remoting_invoke (res);
2805 if (method->is_inflated) {
2806 /* Have to inflate the result */
2807 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, error);
2815 do_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2817 MONO_REQ_GC_UNSAFE_MODE;
2819 MonoObject *result = NULL;
2821 g_assert (callbacks.runtime_invoke);
2825 MONO_PROFILER_RAISE (method_begin_invoke, (method));
2827 result = callbacks.runtime_invoke (method, obj, params, exc, error);
2829 MONO_PROFILER_RAISE (method_end_invoke, (method));
2831 if (!mono_error_ok (error))
2838 * mono_runtime_invoke:
2839 * \param method method to invoke
2840 * \param obj object instance
2841 * \param params arguments to the method
2842 * \param exc exception information.
2843 * Invokes the method represented by \p method on the object \p obj.
2844 * \p obj is the \c this pointer, it should be NULL for static
2845 * methods, a \c MonoObject* for object instances and a pointer to
2846 * the value type for value types.
2848 * The params array contains the arguments to the method with the
2849 * same convention: \c MonoObject* pointers for object instances and
2850 * pointers to the value type otherwise.
2852 * From unmanaged code you'll usually use the
2853 * \c mono_runtime_invoke variant.
2855 * Note that this function doesn't handle virtual methods for
2856 * you, it will exec the exact method you pass: we still need to
2857 * expose a function to lookup the derived class implementation
2858 * of a virtual method (there are examples of this in the code,
2861 * You can pass NULL as the \p exc argument if you don't want to
2862 * catch exceptions, otherwise, \c *exc will be set to the exception
2863 * thrown, if any. if an exception is thrown, you can't use the
2864 * \c MonoObject* result from the function.
2866 * If the method returns a value type, it is boxed in an object
2870 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2875 res = mono_runtime_try_invoke (method, obj, params, exc, &error);
2876 if (*exc == NULL && !mono_error_ok(&error)) {
2877 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
2879 mono_error_cleanup (&error);
2881 res = mono_runtime_invoke_checked (method, obj, params, &error);
2882 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
2888 * mono_runtime_try_invoke:
2889 * \param method method to invoke
2890 * \param obj object instance
2891 * \param params arguments to the method
2892 * \param exc exception information.
2893 * \param error set on error
2894 * Invokes the method represented by \p method on the object \p obj.
2896 * \p obj is the \c this pointer, it should be NULL for static
2897 * methods, a \c MonoObject* for object instances and a pointer to
2898 * the value type for value types.
2900 * The params array contains the arguments to the method with the
2901 * same convention: \c MonoObject* pointers for object instances and
2902 * pointers to the value type otherwise.
2904 * From unmanaged code you'll usually use the
2905 * mono_runtime_invoke() variant.
2907 * Note that this function doesn't handle virtual methods for
2908 * you, it will exec the exact method you pass: we still need to
2909 * expose a function to lookup the derived class implementation
2910 * of a virtual method (there are examples of this in the code,
2913 * For this function, you must not pass NULL as the \p exc argument if
2914 * you don't want to catch exceptions, use
2915 * mono_runtime_invoke_checked(). If an exception is thrown, you
2916 * can't use the \c MonoObject* result from the function.
2918 * If this method cannot be invoked, \p error will be set and \p exc and
2919 * the return value must not be used.
2921 * If the method returns a value type, it is boxed in an object
2925 mono_runtime_try_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError* error)
2927 MONO_REQ_GC_UNSAFE_MODE;
2929 g_assert (exc != NULL);
2931 if (mono_runtime_get_no_exec ())
2932 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2934 return do_runtime_invoke (method, obj, params, exc, error);
2938 * mono_runtime_invoke_checked:
2939 * \param method method to invoke
2940 * \param obj object instance
2941 * \param params arguments to the method
2942 * \param error set on error
2943 * Invokes the method represented by \p method on the object \p obj.
2945 * \p obj is the \c this pointer, it should be NULL for static
2946 * methods, a \c MonoObject* for object instances and a pointer to
2947 * the value type for value types.
2949 * The \p params array contains the arguments to the method with the
2950 * same convention: \c MonoObject* pointers for object instances and
2951 * pointers to the value type otherwise.
2953 * From unmanaged code you'll usually use the
2954 * mono_runtime_invoke() variant.
2956 * Note that this function doesn't handle virtual methods for
2957 * you, it will exec the exact method you pass: we still need to
2958 * expose a function to lookup the derived class implementation
2959 * of a virtual method (there are examples of this in the code,
2962 * If an exception is thrown, you can't use the \c MonoObject* result
2963 * from the function.
2965 * If this method cannot be invoked, \p error will be set. If the
2966 * method throws an exception (and we're in coop mode) the exception
2967 * will be set in \p error.
2969 * If the method returns a value type, it is boxed in an object
2973 mono_runtime_invoke_checked (MonoMethod *method, void *obj, void **params, MonoError* error)
2975 MONO_REQ_GC_UNSAFE_MODE;
2977 if (mono_runtime_get_no_exec ())
2978 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2980 return do_runtime_invoke (method, obj, params, NULL, error);
2984 * mono_method_get_unmanaged_thunk:
2985 * \param method method to generate a thunk for.
2987 * Returns an \c unmanaged->managed thunk that can be used to call
2988 * a managed method directly from C.
2990 * The thunk's C signature closely matches the managed signature:
2992 * C#: <code>public bool Equals (object obj);</code>
2994 * C: <code>typedef MonoBoolean (*Equals)(MonoObject*, MonoObject*, MonoException**);</code>
2996 * The 1st (<code>this</code>) parameter must not be used with static methods:
2998 * C#: <code>public static bool ReferenceEquals (object a, object b);</code>
3000 * C: <code>typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*, MonoException**);</code>
3002 * The last argument must be a non-null \c MonoException* pointer.
3003 * It has "out" semantics. After invoking the thunk, \c *ex will be NULL if no
3004 * exception has been thrown in managed code. Otherwise it will point
3005 * to the \c MonoException* caught by the thunk. In this case, the result of
3006 * the thunk is undefined:
3009 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
3011 * MonoException *ex = NULL;
3013 * Equals func = mono_method_get_unmanaged_thunk (method);
3015 * MonoBoolean res = func (thisObj, objToCompare, &ex);
3019 * // handle exception
3024 * The calling convention of the thunk matches the platform's default
3025 * convention. This means that under Windows, C declarations must
3026 * contain the \c __stdcall attribute:
3028 * C: <code>typedef MonoBoolean (__stdcall *Equals)(MonoObject*, MonoObject*, MonoException**);</code>
3032 * Value type arguments and return values are treated as they were objects:
3034 * C#: <code>public static Rectangle Intersect (Rectangle a, Rectangle b);</code>
3035 * C: <code>typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);</code>
3037 * Arguments must be properly boxed upon trunk's invocation, while return
3038 * values must be unboxed.
3041 mono_method_get_unmanaged_thunk (MonoMethod *method)
3043 MONO_REQ_GC_NEUTRAL_MODE;
3044 MONO_REQ_API_ENTRYPOINT;
3049 g_assert (!mono_threads_is_coop_enabled ());
3051 MONO_ENTER_GC_UNSAFE;
3052 method = mono_marshal_get_thunk_invoke_wrapper (method);
3053 res = mono_compile_method_checked (method, &error);
3054 mono_error_cleanup (&error);
3055 MONO_EXIT_GC_UNSAFE;
3061 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
3063 MONO_REQ_GC_UNSAFE_MODE;
3067 /* object fields cannot be byref, so we don't need a
3069 gpointer *p = (gpointer*)dest;
3076 case MONO_TYPE_BOOLEAN:
3078 case MONO_TYPE_U1: {
3079 guint8 *p = (guint8*)dest;
3080 *p = value ? *(guint8*)value : 0;
3085 case MONO_TYPE_CHAR: {
3086 guint16 *p = (guint16*)dest;
3087 *p = value ? *(guint16*)value : 0;
3090 #if SIZEOF_VOID_P == 4
3095 case MONO_TYPE_U4: {
3096 gint32 *p = (gint32*)dest;
3097 *p = value ? *(gint32*)value : 0;
3100 #if SIZEOF_VOID_P == 8
3105 case MONO_TYPE_U8: {
3106 gint64 *p = (gint64*)dest;
3107 *p = value ? *(gint64*)value : 0;
3110 case MONO_TYPE_R4: {
3111 float *p = (float*)dest;
3112 *p = value ? *(float*)value : 0;
3115 case MONO_TYPE_R8: {
3116 double *p = (double*)dest;
3117 *p = value ? *(double*)value : 0;
3120 case MONO_TYPE_STRING:
3121 case MONO_TYPE_SZARRAY:
3122 case MONO_TYPE_CLASS:
3123 case MONO_TYPE_OBJECT:
3124 case MONO_TYPE_ARRAY:
3125 mono_gc_wbarrier_generic_store (dest, deref_pointer ? *(MonoObject **)value : (MonoObject *)value);
3127 case MONO_TYPE_FNPTR:
3128 case MONO_TYPE_PTR: {
3129 gpointer *p = (gpointer*)dest;
3130 *p = deref_pointer? *(gpointer*)value: value;
3133 case MONO_TYPE_VALUETYPE:
3134 /* note that 't' and 'type->type' can be different */
3135 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3136 t = mono_class_enum_basetype (type->data.klass)->type;
3139 MonoClass *klass = mono_class_from_mono_type (type);
3140 int size = mono_class_value_size (klass, NULL);
3142 mono_gc_bzero_atomic (dest, size);
3144 mono_gc_wbarrier_value_copy (dest, value, 1, klass);
3147 case MONO_TYPE_GENERICINST:
3148 t = type->data.generic_class->container_class->byval_arg.type;
3151 g_error ("got type %x", type->type);
3156 * mono_field_set_value:
3157 * \param obj Instance object
3158 * \param field \c MonoClassField describing the field to set
3159 * \param value The value to be set
3161 * Sets the value of the field described by \p field in the object instance \p obj
3162 * to the value passed in \p value. This method should only be used for instance
3163 * fields. For static fields, use \c mono_field_static_set_value.
3165 * The value must be in the native format of the field type.
3168 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3170 MONO_REQ_GC_UNSAFE_MODE;
3174 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3176 dest = (char*)obj + field->offset;
3177 mono_copy_value (field->type, dest, value, FALSE);
3181 * mono_field_static_set_value:
3182 * \param field \c MonoClassField describing the field to set
3183 * \param value The value to be set
3184 * Sets the value of the static field described by \p field
3185 * to the value passed in \p value.
3186 * The value must be in the native format of the field type.
3189 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3191 MONO_REQ_GC_UNSAFE_MODE;
3195 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3196 /* you cant set a constant! */
3197 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3199 if (field->offset == -1) {
3200 /* Special static */
3203 mono_domain_lock (vt->domain);
3204 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3205 mono_domain_unlock (vt->domain);
3206 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3208 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3210 mono_copy_value (field->type, dest, value, FALSE);
3214 * mono_vtable_get_static_field_data:
3216 * Internal use function: return a pointer to the memory holding the static fields
3217 * for a class or NULL if there are no static fields.
3218 * This is exported only for use by the debugger.
3221 mono_vtable_get_static_field_data (MonoVTable *vt)
3223 MONO_REQ_GC_NEUTRAL_MODE
3225 if (!vt->has_static_fields)
3227 return vt->vtable [vt->klass->vtable_size];
3231 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3233 MONO_REQ_GC_UNSAFE_MODE;
3237 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3238 if (field->offset == -1) {
3239 /* Special static */
3242 mono_domain_lock (vt->domain);
3243 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3244 mono_domain_unlock (vt->domain);
3245 src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3247 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3250 src = (guint8*)obj + field->offset;
3257 * mono_field_get_value:
3258 * \param obj Object instance
3259 * \param field \c MonoClassField describing the field to fetch information from
3260 * \param value pointer to the location where the value will be stored
3261 * Use this routine to get the value of the field \p field in the object
3264 * The pointer provided by value must be of the field type, for reference
3265 * types this is a \c MonoObject*, for value types its the actual pointer to
3273 * mono_field_get_value (obj, int_field, &i);
3277 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3279 MONO_REQ_GC_UNSAFE_MODE;
3285 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3287 src = (char*)obj + field->offset;
3288 mono_copy_value (field->type, value, src, TRUE);
3292 * mono_field_get_value_object:
3293 * \param domain domain where the object will be created (if boxing)
3294 * \param field \c MonoClassField describing the field to fetch information from
3295 * \param obj The object instance for the field.
3296 * \returns a new \c MonoObject with the value from the given field. If the
3297 * field represents a value type, the value is boxed.
3300 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3303 MonoObject* result = mono_field_get_value_object_checked (domain, field, obj, &error);
3304 mono_error_assert_ok (&error);
3309 * mono_field_get_value_object_checked:
3310 * \param domain domain where the object will be created (if boxing)
3311 * \param field \c MonoClassField describing the field to fetch information from
3312 * \param obj The object instance for the field.
3313 * \param error Set on error.
3314 * \returns a new \c MonoObject with the value from the given field. If the
3315 * field represents a value type, the value is boxed. On error returns NULL and sets \p error.
3318 mono_field_get_value_object_checked (MonoDomain *domain, MonoClassField *field, MonoObject *obj, MonoError *error)
3320 MONO_REQ_GC_UNSAFE_MODE;
3326 MonoVTable *vtable = NULL;
3328 gboolean is_static = FALSE;
3329 gboolean is_ref = FALSE;
3330 gboolean is_literal = FALSE;
3331 gboolean is_ptr = FALSE;
3332 MonoType *type = mono_field_get_type_checked (field, error);
3334 return_val_if_nok (error, NULL);
3336 switch (type->type) {
3337 case MONO_TYPE_STRING:
3338 case MONO_TYPE_OBJECT:
3339 case MONO_TYPE_CLASS:
3340 case MONO_TYPE_ARRAY:
3341 case MONO_TYPE_SZARRAY:
3346 case MONO_TYPE_BOOLEAN:
3349 case MONO_TYPE_CHAR:
3358 case MONO_TYPE_VALUETYPE:
3359 is_ref = type->byref;
3361 case MONO_TYPE_GENERICINST:
3362 is_ref = !mono_type_generic_inst_is_valuetype (type);
3368 g_error ("type 0x%x not handled in "
3369 "mono_field_get_value_object", type->type);
3373 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3376 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3380 vtable = mono_class_vtable_full (domain, field->parent, error);
3381 return_val_if_nok (error, NULL);
3383 if (!vtable->initialized) {
3384 mono_runtime_class_init_full (vtable, error);
3385 return_val_if_nok (error, NULL);
3394 get_default_field_value (domain, field, &o, error);
3395 return_val_if_nok (error, NULL);
3396 } else if (is_static) {
3397 mono_field_static_get_value_checked (vtable, field, &o, error);
3398 return_val_if_nok (error, NULL);
3400 mono_field_get_value (obj, field, &o);
3406 static MonoMethod *m;
3412 MonoClass *ptr_klass = mono_class_get_pointer_class ();
3413 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3419 get_default_field_value (domain, field, v, error);
3420 return_val_if_nok (error, NULL);
3421 } else if (is_static) {
3422 mono_field_static_get_value_checked (vtable, field, v, error);
3423 return_val_if_nok (error, NULL);
3425 mono_field_get_value (obj, field, v);
3428 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3429 args [0] = ptr ? *ptr : NULL;
3430 args [1] = mono_type_get_object_checked (mono_domain_get (), type, error);
3431 return_val_if_nok (error, NULL);
3433 o = mono_runtime_invoke_checked (m, NULL, args, error);
3434 return_val_if_nok (error, NULL);
3439 /* boxed value type */
3440 klass = mono_class_from_mono_type (type);
3442 if (mono_class_is_nullable (klass))
3443 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass, error);
3445 o = mono_object_new_checked (domain, klass, error);
3446 return_val_if_nok (error, NULL);
3447 v = ((gchar *) o) + sizeof (MonoObject);
3450 get_default_field_value (domain, field, v, error);
3451 return_val_if_nok (error, NULL);
3452 } else if (is_static) {
3453 mono_field_static_get_value_checked (vtable, field, v, error);
3454 return_val_if_nok (error, NULL);
3456 mono_field_get_value (obj, field, v);
3463 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value, MonoError *error)
3465 MONO_REQ_GC_UNSAFE_MODE;
3469 const char *p = blob;
3470 mono_metadata_decode_blob_size (p, &p);
3473 case MONO_TYPE_BOOLEAN:
3476 *(guint8 *) value = *p;
3478 case MONO_TYPE_CHAR:
3481 *(guint16*) value = read16 (p);
3485 *(guint32*) value = read32 (p);
3489 *(guint64*) value = read64 (p);
3492 readr4 (p, (float*) value);
3495 readr8 (p, (double*) value);
3497 case MONO_TYPE_STRING:
3498 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob, error);
3500 case MONO_TYPE_CLASS:
3501 *(gpointer*) value = NULL;
3505 g_warning ("type 0x%02x should not be in constant table", type);
3511 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error)
3513 MONO_REQ_GC_NEUTRAL_MODE;
3515 MonoTypeEnum def_type;
3520 data = mono_class_get_field_default_value (field, &def_type);
3521 mono_get_constant_value_from_blob (domain, def_type, data, value, error);
3525 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3527 MONO_REQ_GC_UNSAFE_MODE;
3533 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3535 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3536 get_default_field_value (vt->domain, field, value, error);
3540 if (field->offset == -1) {
3541 /* Special static */
3542 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3543 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3545 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3547 mono_copy_value (field->type, value, src, TRUE);
3551 * mono_field_static_get_value:
3552 * \param vt vtable to the object
3553 * \param field \c MonoClassField describing the field to fetch information from
3554 * \param value where the value is returned
3555 * Use this routine to get the value of the static field \p field value.
3557 * The pointer provided by value must be of the field type, for reference
3558 * types this is a \c MonoObject*, for value types its the actual pointer to
3566 * mono_field_static_get_value (vt, int_field, &i);
3570 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3572 MONO_REQ_GC_NEUTRAL_MODE;
3575 mono_field_static_get_value_checked (vt, field, value, &error);
3576 mono_error_cleanup (&error);
3580 * mono_field_static_get_value_checked:
3581 * \param vt vtable to the object
3582 * \param field \c MonoClassField describing the field to fetch information from
3583 * \param value where the value is returned
3584 * \param error set on error
3585 * Use this routine to get the value of the static field \p field value.
3587 * The pointer provided by value must be of the field type, for reference
3588 * types this is a \c MonoObject*, for value types its the actual pointer to
3593 * mono_field_static_get_value_checked (vt, int_field, &i, error);
3594 * if (!is_ok (error)) { ... }
3596 * On failure sets \p error.
3599 mono_field_static_get_value_checked (MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3601 MONO_REQ_GC_NEUTRAL_MODE;
3603 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value, error);
3607 * mono_property_set_value:
3608 * \param prop MonoProperty to set
3609 * \param obj instance object on which to act
3610 * \param params parameters to pass to the propery
3611 * \param exc optional exception
3612 * Invokes the property's set method with the given arguments on the
3613 * object instance obj (or NULL for static properties).
3615 * You can pass NULL as the exc argument if you don't want to
3616 * catch exceptions, otherwise, \c *exc will be set to the exception
3617 * thrown, if any. if an exception is thrown, you can't use the
3618 * \c MonoObject* result from the function.
3621 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3623 MONO_REQ_GC_UNSAFE_MODE;
3626 do_runtime_invoke (prop->set, obj, params, exc, &error);
3627 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3628 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3630 mono_error_cleanup (&error);
3635 * mono_property_set_value_checked:
3636 * \param prop \c MonoProperty to set
3637 * \param obj instance object on which to act
3638 * \param params parameters to pass to the propery
3639 * \param error set on error
3640 * Invokes the property's set method with the given arguments on the
3641 * object instance \p obj (or NULL for static properties).
3642 * \returns TRUE on success. On failure returns FALSE and sets \p error.
3643 * If an exception is thrown, it will be caught and returned via \p error.
3646 mono_property_set_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3648 MONO_REQ_GC_UNSAFE_MODE;
3653 do_runtime_invoke (prop->set, obj, params, &exc, error);
3654 if (exc != NULL && is_ok (error))
3655 mono_error_set_exception_instance (error, (MonoException*)exc);
3656 return is_ok (error);
3660 * mono_property_get_value:
3661 * \param prop \c MonoProperty to fetch
3662 * \param obj instance object on which to act
3663 * \param params parameters to pass to the propery
3664 * \param exc optional exception
3665 * Invokes the property's \c get method with the given arguments on the
3666 * object instance \p obj (or NULL for static properties).
3668 * You can pass NULL as the \p exc argument if you don't want to
3669 * catch exceptions, otherwise, \c *exc will be set to the exception
3670 * thrown, if any. if an exception is thrown, you can't use the
3671 * \c MonoObject* result from the function.
3673 * \returns the value from invoking the \c get method on the property.
3676 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3678 MONO_REQ_GC_UNSAFE_MODE;
3681 MonoObject *val = do_runtime_invoke (prop->get, obj, params, exc, &error);
3682 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3683 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3685 mono_error_cleanup (&error); /* FIXME don't raise here */
3692 * mono_property_get_value_checked:
3693 * \param prop \c MonoProperty to fetch
3694 * \param obj instance object on which to act
3695 * \param params parameters to pass to the propery
3696 * \param error set on error
3697 * Invokes the property's \c get method with the given arguments on the
3698 * object instance obj (or NULL for static properties).
3700 * If an exception is thrown, you can't use the
3701 * \c MonoObject* result from the function. The exception will be propagated via \p error.
3703 * \returns the value from invoking the get method on the property. On
3704 * failure returns NULL and sets \p error.
3707 mono_property_get_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3709 MONO_REQ_GC_UNSAFE_MODE;
3712 MonoObject *val = do_runtime_invoke (prop->get, obj, params, &exc, error);
3713 if (exc != NULL && !is_ok (error))
3714 mono_error_set_exception_instance (error, (MonoException*) exc);
3722 * mono_nullable_init:
3723 * @buf: The nullable structure to initialize.
3724 * @value: the value to initialize from
3725 * @klass: the type for the object
3727 * Initialize the nullable structure pointed to by @buf from @value which
3728 * should be a boxed value type. The size of @buf should be able to hold
3729 * as much data as the @klass->instance_size (which is the number of bytes
3730 * that will be copies).
3732 * Since Nullables have variable structure, we can not define a C
3733 * structure for them.
3736 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3738 MONO_REQ_GC_UNSAFE_MODE;
3740 MonoClass *param_class = klass->cast_class;
3742 mono_class_setup_fields (klass);
3743 g_assert (klass->fields_inited);
3745 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3746 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3748 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3750 if (param_class->has_references)
3751 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3753 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3755 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3760 * mono_nullable_init_from_handle:
3761 * @buf: The nullable structure to initialize.
3762 * @value: the value to initialize from
3763 * @klass: the type for the object
3765 * Initialize the nullable structure pointed to by @buf from @value which
3766 * should be a boxed value type. The size of @buf should be able to hold
3767 * as much data as the @klass->instance_size (which is the number of bytes
3768 * that will be copies).
3770 * Since Nullables have variable structure, we can not define a C
3771 * structure for them.
3774 mono_nullable_init_from_handle (guint8 *buf, MonoObjectHandle value, MonoClass *klass)
3776 MONO_REQ_GC_UNSAFE_MODE;
3778 MonoClass *param_class = klass->cast_class;
3780 mono_class_setup_fields (klass);
3781 g_assert (klass->fields_inited);
3783 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3784 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3786 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = MONO_HANDLE_IS_NULL (value) ? 0 : 1;
3787 if (!MONO_HANDLE_IS_NULL (value)) {
3788 uint32_t value_gchandle = 0;
3789 gpointer src = mono_object_handle_pin_unbox (value, &value_gchandle);
3790 if (param_class->has_references)
3791 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), src, 1, param_class);
3793 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), src, mono_class_value_size (param_class, NULL));
3794 mono_gchandle_free (value_gchandle);
3796 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3803 * mono_nullable_box:
3804 * \param buf The buffer representing the data to be boxed
3805 * \param klass the type to box it as.
3806 * \param error set on error
3808 * Creates a boxed vtype or NULL from the \c Nullable structure pointed to by
3809 * \p buf. On failure returns NULL and sets \p error.
3812 mono_nullable_box (guint8 *buf, MonoClass *klass, MonoError *error)
3814 MONO_REQ_GC_UNSAFE_MODE;
3817 MonoClass *param_class = klass->cast_class;
3819 mono_class_setup_fields (klass);
3820 g_assert (klass->fields_inited);
3822 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3823 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3825 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3826 MonoObject *o = mono_object_new_checked (mono_domain_get (), param_class, error);
3827 return_val_if_nok (error, NULL);
3828 if (param_class->has_references)
3829 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3831 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3839 * mono_get_delegate_invoke:
3840 * \param klass The delegate class
3841 * \returns the \c MonoMethod for the \c Invoke method in the delegate class or NULL if \p klass is a broken delegate type
3844 mono_get_delegate_invoke (MonoClass *klass)
3846 MONO_REQ_GC_NEUTRAL_MODE;
3850 /* This is called at runtime, so avoid the slower search in metadata */
3851 mono_class_setup_methods (klass);
3852 if (mono_class_has_failure (klass))
3854 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3859 * mono_get_delegate_begin_invoke:
3860 * \param klass The delegate class
3861 * \returns the \c MonoMethod for the \c BeginInvoke method in the delegate class or NULL if \p klass is a broken delegate type
3864 mono_get_delegate_begin_invoke (MonoClass *klass)
3866 MONO_REQ_GC_NEUTRAL_MODE;
3870 /* This is called at runtime, so avoid the slower search in metadata */
3871 mono_class_setup_methods (klass);
3872 if (mono_class_has_failure (klass))
3874 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3879 * mono_get_delegate_end_invoke:
3880 * \param klass The delegate class
3881 * \returns the \c MonoMethod for the \c EndInvoke method in the delegate class or NULL if \p klass is a broken delegate type
3884 mono_get_delegate_end_invoke (MonoClass *klass)
3886 MONO_REQ_GC_NEUTRAL_MODE;
3890 /* This is called at runtime, so avoid the slower search in metadata */
3891 mono_class_setup_methods (klass);
3892 if (mono_class_has_failure (klass))
3894 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3899 * mono_runtime_delegate_invoke:
3900 * \param delegate pointer to a delegate object.
3901 * \param params parameters for the delegate.
3902 * \param exc Pointer to the exception result.
3904 * Invokes the delegate method \p delegate with the parameters provided.
3906 * You can pass NULL as the \p exc argument if you don't want to
3907 * catch exceptions, otherwise, \c *exc will be set to the exception
3908 * thrown, if any. if an exception is thrown, you can't use the
3909 * \c MonoObject* result from the function.
3912 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3914 MONO_REQ_GC_UNSAFE_MODE;
3918 MonoObject *result = mono_runtime_delegate_try_invoke (delegate, params, exc, &error);
3920 mono_error_cleanup (&error);
3923 if (!is_ok (&error))
3924 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
3928 MonoObject *result = mono_runtime_delegate_invoke_checked (delegate, params, &error);
3929 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
3935 * mono_runtime_delegate_try_invoke:
3936 * \param delegate pointer to a delegate object.
3937 * \param params parameters for the delegate.
3938 * \param exc Pointer to the exception result.
3939 * \param error set on error
3940 * Invokes the delegate method \p delegate with the parameters provided.
3942 * You can pass NULL as the \p exc argument if you don't want to
3943 * catch exceptions, otherwise, \c *exc will be set to the exception
3944 * thrown, if any. On failure to execute, \p error will be set.
3945 * if an exception is thrown, you can't use the
3946 * \c MonoObject* result from the function.
3949 mono_runtime_delegate_try_invoke (MonoObject *delegate, void **params, MonoObject **exc, MonoError *error)
3951 MONO_REQ_GC_UNSAFE_MODE;
3955 MonoClass *klass = delegate->vtable->klass;
3958 im = mono_get_delegate_invoke (klass);
3960 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3963 o = mono_runtime_try_invoke (im, delegate, params, exc, error);
3965 o = mono_runtime_invoke_checked (im, delegate, params, error);
3972 * mono_runtime_delegate_invoke_checked:
3973 * \param delegate pointer to a delegate object.
3974 * \param params parameters for the delegate.
3975 * \param error set on error
3976 * Invokes the delegate method \p delegate with the parameters provided.
3977 * On failure \p error will be set and you can't use the \c MonoObject*
3978 * result from the function.
3981 mono_runtime_delegate_invoke_checked (MonoObject *delegate, void **params, MonoError *error)
3984 return mono_runtime_delegate_try_invoke (delegate, params, NULL, error);
3987 static char **main_args = NULL;
3988 static int num_main_args = 0;
3991 * mono_runtime_get_main_args:
3992 * \returns A \c MonoArray with the arguments passed to the main program
3995 mono_runtime_get_main_args (void)
3997 MONO_REQ_GC_UNSAFE_MODE;
3999 MonoArray *result = mono_runtime_get_main_args_checked (&error);
4000 mono_error_assert_ok (&error);
4005 * mono_runtime_get_main_args_checked:
4006 * \param error set on error
4007 * \returns a \c MonoArray with the arguments passed to the main
4008 * program. On failure returns NULL and sets \p error.
4011 mono_runtime_get_main_args_checked (MonoError *error)
4015 MonoDomain *domain = mono_domain_get ();
4019 res = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, num_main_args, error);
4020 return_val_if_nok (error, NULL);
4022 for (i = 0; i < num_main_args; ++i) {
4023 MonoString *arg = mono_string_new_checked (domain, main_args [i], error);
4024 return_val_if_nok (error, NULL);
4025 mono_array_setref (res, i, arg);
4032 free_main_args (void)
4034 MONO_REQ_GC_NEUTRAL_MODE;
4038 for (i = 0; i < num_main_args; ++i)
4039 g_free (main_args [i]);
4046 * mono_runtime_set_main_args:
4047 * \param argc number of arguments from the command line
4048 * \param argv array of strings from the command line
4049 * Set the command line arguments from an embedding application that doesn't otherwise call
4050 * \c mono_runtime_run_main.
4053 mono_runtime_set_main_args (int argc, char* argv[])
4055 MONO_REQ_GC_NEUTRAL_MODE;
4060 main_args = g_new0 (char*, argc);
4061 num_main_args = argc;
4063 for (i = 0; i < argc; ++i) {
4066 utf8_arg = mono_utf8_from_external (argv[i]);
4067 if (utf8_arg == NULL) {
4068 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
4069 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4073 main_args [i] = utf8_arg;
4080 * Prepare an array of arguments in order to execute a standard Main()
4081 * method (argc/argv contains the executable name). This method also
4082 * sets the command line argument value needed by System.Environment.
4086 prepare_run_main (MonoMethod *method, int argc, char *argv[])
4088 MONO_REQ_GC_UNSAFE_MODE;
4092 MonoArray *args = NULL;
4093 MonoDomain *domain = mono_domain_get ();
4094 gchar *utf8_fullpath;
4095 MonoMethodSignature *sig;
4097 g_assert (method != NULL);
4099 mono_thread_set_main (mono_thread_current ());
4101 main_args = g_new0 (char*, argc);
4102 num_main_args = argc;
4104 if (!g_path_is_absolute (argv [0])) {
4105 gchar *basename = g_path_get_basename (argv [0]);
4106 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
4110 utf8_fullpath = mono_utf8_from_external (fullpath);
4111 if(utf8_fullpath == NULL) {
4112 /* Printing the arg text will cause glib to
4113 * whinge about "Invalid UTF-8", but at least
4114 * its relevant, and shows the problem text
4117 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
4118 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4125 utf8_fullpath = mono_utf8_from_external (argv[0]);
4126 if(utf8_fullpath == NULL) {
4127 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
4128 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4133 main_args [0] = utf8_fullpath;
4135 for (i = 1; i < argc; ++i) {
4138 utf8_arg=mono_utf8_from_external (argv[i]);
4139 if(utf8_arg==NULL) {
4140 /* Ditto the comment about Invalid UTF-8 here */
4141 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
4142 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4146 main_args [i] = utf8_arg;
4151 sig = mono_method_signature (method);
4153 g_print ("Unable to load Main method.\n");
4157 if (sig->param_count) {
4158 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, argc, &error);
4159 mono_error_assert_ok (&error);
4160 for (i = 0; i < argc; ++i) {
4161 /* The encodings should all work, given that
4162 * we've checked all these args for the
4165 gchar *str = mono_utf8_from_external (argv [i]);
4166 MonoString *arg = mono_string_new_checked (domain, str, &error);
4167 mono_error_assert_ok (&error);
4168 mono_array_setref (args, i, arg);
4172 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, 0, &error);
4173 mono_error_assert_ok (&error);
4176 mono_assembly_set_main (method->klass->image->assembly);
4182 * mono_runtime_run_main:
4183 * \param method the method to start the application with (usually <code>Main</code>)
4184 * \param argc number of arguments from the command line
4185 * \param argv array of strings from the command line
4186 * \param exc excetption results
4187 * Execute a standard \c Main method (\p argc / \p argv contains the
4188 * executable name). This method also sets the command line argument value
4189 * needed by \c System.Environment.
4192 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
4195 MONO_REQ_GC_UNSAFE_MODE;
4198 MonoArray *args = prepare_run_main (method, argc, argv);
4201 res = mono_runtime_try_exec_main (method, args, exc);
4203 res = mono_runtime_exec_main_checked (method, args, &error);
4204 mono_error_raise_exception (&error); /* OK to throw, external only without a better alternative */
4210 * mono_runtime_run_main_checked:
4211 * \param method the method to start the application with (usually \c Main)
4212 * \param argc number of arguments from the command line
4213 * \param argv array of strings from the command line
4214 * \param error set on error
4216 * Execute a standard \c Main method (\p argc / \p argv contains the
4217 * executable name). This method also sets the command line argument value
4218 * needed by \c System.Environment. On failure sets \p error.
4221 mono_runtime_run_main_checked (MonoMethod *method, int argc, char* argv[],
4225 MonoArray *args = prepare_run_main (method, argc, argv);
4226 return mono_runtime_exec_main_checked (method, args, error);
4230 * mono_runtime_try_run_main:
4231 * \param method the method to start the application with (usually \c Main)
4232 * \param argc number of arguments from the command line
4233 * \param argv array of strings from the command line
4234 * \param exc set if \c Main throws an exception
4235 * \param error set if \c Main can't be executed
4236 * Execute a standard \c Main method (\p argc / \p argv contains the executable
4237 * name). This method also sets the command line argument value needed
4238 * by \c System.Environment. On failure sets \p error if Main can't be
4239 * executed or \p exc if it threw an exception.
4242 mono_runtime_try_run_main (MonoMethod *method, int argc, char* argv[],
4246 MonoArray *args = prepare_run_main (method, argc, argv);
4247 return mono_runtime_try_exec_main (method, args, exc);
4252 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4254 static MonoMethod *serialize_method;
4260 if (!serialize_method) {
4261 MonoClass *klass = mono_class_get_remoting_services_class ();
4262 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
4265 if (!serialize_method) {
4270 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
4275 array = mono_runtime_try_invoke (serialize_method, NULL, params, exc, &error);
4276 if (*exc == NULL && !mono_error_ok (&error))
4277 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert serialize_object to MonoError */
4279 mono_error_cleanup (&error);
4288 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4290 MONO_REQ_GC_UNSAFE_MODE;
4292 static MonoMethod *deserialize_method;
4298 if (!deserialize_method) {
4299 MonoClass *klass = mono_class_get_remoting_services_class ();
4300 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
4302 if (!deserialize_method) {
4310 result = mono_runtime_try_invoke (deserialize_method, NULL, params, exc, &error);
4311 if (*exc == NULL && !mono_error_ok (&error))
4312 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert deserialize_object to MonoError */
4314 mono_error_cleanup (&error);
4322 #ifndef DISABLE_REMOTING
4324 make_transparent_proxy (MonoObject *obj, MonoError *error)
4326 MONO_REQ_GC_UNSAFE_MODE;
4328 static MonoMethod *get_proxy_method;
4330 MonoDomain *domain = mono_domain_get ();
4331 MonoRealProxy *real_proxy;
4332 MonoReflectionType *reflection_type;
4333 MonoTransparentProxy *transparent_proxy;
4337 if (!get_proxy_method)
4338 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
4340 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
4342 real_proxy = (MonoRealProxy*) mono_object_new_checked (domain, mono_defaults.real_proxy_class, error);
4343 return_val_if_nok (error, NULL);
4344 reflection_type = mono_type_get_object_checked (domain, &obj->vtable->klass->byval_arg, error);
4345 return_val_if_nok (error, NULL);
4347 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
4348 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
4350 MonoObject *exc = NULL;
4352 transparent_proxy = (MonoTransparentProxy*) mono_runtime_try_invoke (get_proxy_method, real_proxy, NULL, &exc, error);
4353 if (exc != NULL && is_ok (error))
4354 mono_error_set_exception_instance (error, (MonoException*)exc);
4356 return (MonoObject*) transparent_proxy;
4358 #endif /* DISABLE_REMOTING */
4361 * mono_object_xdomain_representation
4362 * \param obj an object
4363 * \param target_domain a domain
4364 * \param error set on error.
4365 * Creates a representation of obj in the domain \p target_domain. This
4366 * is either a copy of \p obj arrived through via serialization and
4367 * deserialization or a proxy, depending on whether the object is
4368 * serializable or marshal by ref. \p obj must not be in \p target_domain.
4369 * If the object cannot be represented in \p target_domain, NULL is
4370 * returned and \p error is set appropriately.
4373 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoError *error)
4375 MONO_REQ_GC_UNSAFE_MODE;
4378 MonoObject *deserialized = NULL;
4380 #ifndef DISABLE_REMOTING
4381 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
4382 deserialized = make_transparent_proxy (obj, error);
4387 gboolean failure = FALSE;
4388 MonoDomain *domain = mono_domain_get ();
4389 MonoObject *serialized;
4390 MonoObject *exc = NULL;
4392 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
4393 serialized = serialize_object (obj, &failure, &exc);
4394 mono_domain_set_internal_with_options (target_domain, FALSE);
4396 deserialized = deserialize_object (serialized, &failure, &exc);
4397 if (domain != target_domain)
4398 mono_domain_set_internal_with_options (domain, FALSE);
4400 mono_error_set_exception_instance (error, (MonoException*)exc);
4403 return deserialized;
4406 /* Used in call_unhandled_exception_delegate */
4408 create_unhandled_exception_eventargs (MonoObject *exc, MonoError *error)
4410 MONO_REQ_GC_UNSAFE_MODE;
4415 MonoMethod *method = NULL;
4416 MonoBoolean is_terminating = TRUE;
4419 klass = mono_class_get_unhandled_exception_event_args_class ();
4420 mono_class_init (klass);
4422 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4423 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
4427 args [1] = &is_terminating;
4429 obj = mono_object_new_checked (mono_domain_get (), klass, error);
4430 return_val_if_nok (error, NULL);
4432 mono_runtime_invoke_checked (method, obj, args, error);
4433 return_val_if_nok (error, NULL);
4438 /* Used in mono_unhandled_exception */
4440 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4441 MONO_REQ_GC_UNSAFE_MODE;
4444 MonoObject *e = NULL;
4446 MonoDomain *current_domain = mono_domain_get ();
4448 if (domain != current_domain)
4449 mono_domain_set_internal_with_options (domain, FALSE);
4451 g_assert (domain == mono_object_domain (domain->domain));
4453 if (mono_object_domain (exc) != domain) {
4455 exc = mono_object_xdomain_representation (exc, domain, &error);
4457 if (!is_ok (&error)) {
4458 MonoError inner_error;
4459 MonoException *serialization_exc = mono_error_convert_to_exception (&error);
4460 exc = mono_object_xdomain_representation ((MonoObject*)serialization_exc, domain, &inner_error);
4461 mono_error_assert_ok (&inner_error);
4463 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4464 "System.Runtime.Serialization", "SerializationException",
4465 "Could not serialize unhandled exception.");
4469 g_assert (mono_object_domain (exc) == domain);
4471 pa [0] = domain->domain;
4472 pa [1] = create_unhandled_exception_eventargs (exc, &error);
4473 mono_error_assert_ok (&error);
4474 mono_runtime_delegate_try_invoke (delegate, pa, &e, &error);
4475 if (!is_ok (&error)) {
4477 e = (MonoObject*)mono_error_convert_to_exception (&error);
4479 mono_error_cleanup (&error);
4482 if (domain != current_domain)
4483 mono_domain_set_internal_with_options (current_domain, FALSE);
4486 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4487 if (!mono_error_ok (&error)) {
4488 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4489 mono_error_cleanup (&error);
4491 g_warning ("exception inside UnhandledException handler: %s\n", msg);
4497 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4500 * mono_runtime_unhandled_exception_policy_set:
4501 * \param policy the new policy
4502 * This is a VM internal routine.
4503 * Sets the runtime policy for handling unhandled exceptions.
4506 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4507 runtime_unhandled_exception_policy = policy;
4511 * mono_runtime_unhandled_exception_policy_get:
4513 * This is a VM internal routine.
4515 * Gets the runtime policy for handling unhandled exceptions.
4517 MonoRuntimeUnhandledExceptionPolicy
4518 mono_runtime_unhandled_exception_policy_get (void) {
4519 return runtime_unhandled_exception_policy;
4523 * mono_unhandled_exception:
4524 * \param exc exception thrown
4525 * This is a VM internal routine.
4527 * We call this function when we detect an unhandled exception
4528 * in the default domain.
4530 * It invokes the \c UnhandledException event in \c AppDomain or prints
4531 * a warning to the console
4534 mono_unhandled_exception (MonoObject *exc_raw)
4537 HANDLE_FUNCTION_ENTER ();
4538 MONO_HANDLE_DCL (MonoObject, exc);
4539 error_init (&error);
4540 mono_unhandled_exception_checked (exc, &error);
4541 mono_error_assert_ok (&error);
4542 HANDLE_FUNCTION_RETURN ();
4546 * mono_unhandled_exception:
4547 * @exc: exception thrown
4549 * This is a VM internal routine.
4551 * We call this function when we detect an unhandled exception
4552 * in the default domain.
4554 * It invokes the * UnhandledException event in AppDomain or prints
4555 * a warning to the console
4558 mono_unhandled_exception_checked (MonoObjectHandle exc, MonoError *error)
4560 MONO_REQ_GC_UNSAFE_MODE;
4563 MonoClassField *field;
4564 MonoDomain *current_domain, *root_domain;
4565 MonoObjectHandle current_appdomain_delegate = MONO_HANDLE_NEW (MonoObject, NULL);
4567 MonoClass *klass = mono_handle_class (exc);
4568 if (mono_class_has_parent (klass, mono_defaults.threadabortexception_class))
4571 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4574 current_domain = mono_domain_get ();
4575 root_domain = mono_get_root_domain ();
4577 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 */
4578 return_if_nok (error);
4579 if (current_domain != root_domain) {
4580 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 */
4581 return_if_nok (error);
4584 if (MONO_HANDLE_IS_NULL (current_appdomain_delegate) && MONO_HANDLE_IS_NULL (root_appdomain_delegate)) {
4585 mono_print_unhandled_exception (MONO_HANDLE_RAW (exc)); /* FIXME use handles for mono_print_unhandled_exception */
4587 /* unhandled exception callbacks must not be aborted */
4588 mono_threads_begin_abort_protected_block ();
4589 if (!MONO_HANDLE_IS_NULL (root_appdomain_delegate))
4590 call_unhandled_exception_delegate (root_domain, MONO_HANDLE_RAW (root_appdomain_delegate), MONO_HANDLE_RAW (exc)); /* FIXME use handles in call_unhandled_exception_delegate */
4591 if (!MONO_HANDLE_IS_NULL (current_appdomain_delegate))
4592 call_unhandled_exception_delegate (current_domain, MONO_HANDLE_RAW (current_appdomain_delegate), MONO_HANDLE_RAW (exc));
4593 mono_threads_end_abort_protected_block ();
4596 /* set exitcode only if we will abort the process */
4597 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4598 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4600 mono_environment_exitcode_set (1);
4605 * mono_runtime_exec_managed_code:
4606 * \param domain Application domain
4607 * \param main_func function to invoke from the execution thread
4608 * \param main_args parameter to the main_func
4609 * Launch a new thread to execute a function
4611 * \p main_func is called back from the thread with main_args as the
4612 * parameter. The callback function is expected to start \c Main
4613 * eventually. This function then waits for all managed threads to
4615 * It is not necessary anymore to execute managed code in a subthread,
4616 * so this function should not be used anymore by default: just
4617 * execute the code and then call mono_thread_manage().
4620 mono_runtime_exec_managed_code (MonoDomain *domain,
4621 MonoMainThreadFunc main_func,
4625 mono_thread_create_checked (domain, main_func, main_args, &error);
4626 mono_error_assert_ok (&error);
4628 mono_thread_manage ();
4632 prepare_thread_to_exec_main (MonoDomain *domain, MonoMethod *method)
4634 MonoInternalThread* thread = mono_thread_internal_current ();
4635 MonoCustomAttrInfo* cinfo;
4636 gboolean has_stathread_attribute;
4638 if (!domain->entry_assembly) {
4641 MonoAssembly *assembly;
4643 assembly = method->klass->image->assembly;
4644 domain->entry_assembly = assembly;
4645 /* Domains created from another domain already have application_base and configuration_file set */
4646 if (domain->setup->application_base == NULL) {
4647 MonoString *basedir = mono_string_new_checked (domain, assembly->basedir, &error);
4648 mono_error_assert_ok (&error);
4649 MONO_OBJECT_SETREF (domain->setup, application_base, basedir);
4652 if (domain->setup->configuration_file == NULL) {
4653 str = g_strconcat (assembly->image->name, ".config", NULL);
4654 MonoString *config_file = mono_string_new_checked (domain, str, &error);
4655 mono_error_assert_ok (&error);
4656 MONO_OBJECT_SETREF (domain->setup, configuration_file, config_file);
4658 mono_domain_set_options_from_config (domain);
4662 MonoError cattr_error;
4663 cinfo = mono_custom_attrs_from_method_checked (method, &cattr_error);
4664 mono_error_cleanup (&cattr_error); /* FIXME warn here? */
4666 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, mono_class_get_sta_thread_attribute_class ());
4668 mono_custom_attrs_free (cinfo);
4670 has_stathread_attribute = FALSE;
4672 if (has_stathread_attribute) {
4673 thread->apartment_state = ThreadApartmentState_STA;
4675 thread->apartment_state = ThreadApartmentState_MTA;
4677 mono_thread_init_apartment_state ();
4682 do_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4684 MONO_REQ_GC_UNSAFE_MODE;
4694 /* FIXME: check signature of method */
4695 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4697 res = mono_runtime_invoke_checked (method, NULL, pa, error);
4699 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4702 mono_environment_exitcode_set (rval);
4704 mono_runtime_invoke_checked (method, NULL, pa, error);
4716 do_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4718 MONO_REQ_GC_UNSAFE_MODE;
4728 /* FIXME: check signature of method */
4729 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4730 MonoError inner_error;
4732 res = mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4733 if (*exc == NULL && !mono_error_ok (&inner_error))
4734 *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4736 mono_error_cleanup (&inner_error);
4739 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4743 mono_environment_exitcode_set (rval);
4745 MonoError inner_error;
4746 mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4747 if (*exc == NULL && !mono_error_ok (&inner_error))
4748 *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4750 mono_error_cleanup (&inner_error);
4755 /* If the return type of Main is void, only
4756 * set the exitcode if an exception was thrown
4757 * (we don't want to blow away an
4758 * explicitly-set exit code)
4761 mono_environment_exitcode_set (rval);
4769 * Execute a standard Main() method (args doesn't contain the
4773 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4776 prepare_thread_to_exec_main (mono_object_domain (args), method);
4778 int rval = do_try_exec_main (method, args, exc);
4781 int rval = do_exec_main_checked (method, args, &error);
4782 mono_error_raise_exception (&error); /* OK to throw, external only with no better option */
4788 * Execute a standard Main() method (args doesn't contain the
4791 * On failure sets @error
4794 mono_runtime_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4797 prepare_thread_to_exec_main (mono_object_domain (args), method);
4798 return do_exec_main_checked (method, args, error);
4802 * Execute a standard Main() method (args doesn't contain the
4805 * On failure sets @error if Main couldn't be executed, or @exc if it threw an exception.
4808 mono_runtime_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4810 prepare_thread_to_exec_main (mono_object_domain (args), method);
4811 return do_try_exec_main (method, args, exc);
4816 /** invoke_array_extract_argument:
4817 * @params: array of arguments to the method.
4818 * @i: the index of the argument to extract.
4819 * @t: ith type from the method signature.
4820 * @has_byref_nullables: outarg - TRUE if method expects a byref nullable argument
4821 * @error: set on error.
4823 * Given an array of method arguments, return the ith one using the corresponding type
4824 * to perform necessary unboxing. If method expects a ref nullable argument, writes TRUE to @has_byref_nullables.
4826 * On failure sets @error and returns NULL.
4829 invoke_array_extract_argument (MonoArray *params, int i, MonoType *t, gboolean* has_byref_nullables, MonoError *error)
4831 MonoType *t_orig = t;
4832 gpointer result = NULL;
4838 case MONO_TYPE_BOOLEAN:
4841 case MONO_TYPE_CHAR:
4850 case MONO_TYPE_VALUETYPE:
4851 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (t_orig))) {
4852 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4853 result = mono_array_get (params, MonoObject*, i);
4855 *has_byref_nullables = TRUE;
4857 /* MS seems to create the objects if a null is passed in */
4858 gboolean was_null = FALSE;
4859 if (!mono_array_get (params, MonoObject*, i)) {
4860 MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (t_orig), error);
4861 return_val_if_nok (error, NULL);
4862 mono_array_setref (params, i, o);
4868 * We can't pass the unboxed vtype byref to the callee, since
4869 * that would mean the callee would be able to modify boxed
4870 * primitive types. So we (and MS) make a copy of the boxed
4871 * object, pass that to the callee, and replace the original
4872 * boxed object in the arg array with the copy.
4874 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4875 MonoObject *copy = mono_value_box_checked (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig), error);
4876 return_val_if_nok (error, NULL);
4877 mono_array_setref (params, i, copy);
4880 result = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4881 if (!t->byref && was_null)
4882 mono_array_setref (params, i, NULL);
4885 case MONO_TYPE_STRING:
4886 case MONO_TYPE_OBJECT:
4887 case MONO_TYPE_CLASS:
4888 case MONO_TYPE_ARRAY:
4889 case MONO_TYPE_SZARRAY:
4891 result = mono_array_addr (params, MonoObject*, i);
4892 // FIXME: I need to check this code path
4894 result = mono_array_get (params, MonoObject*, i);
4896 case MONO_TYPE_GENERICINST:
4898 t = &t->data.generic_class->container_class->this_arg;
4900 t = &t->data.generic_class->container_class->byval_arg;
4902 case MONO_TYPE_PTR: {
4905 /* The argument should be an IntPtr */
4906 arg = mono_array_get (params, MonoObject*, i);
4910 g_assert (arg->vtable->klass == mono_defaults.int_class);
4911 result = ((MonoIntPtr*)arg)->m_value;
4916 g_error ("type 0x%x not handled in mono_runtime_invoke_array", t_orig->type);
4921 * mono_runtime_invoke_array:
4922 * \param method method to invoke
4923 * \param obj object instance
4924 * \param params arguments to the method
4925 * \param exc exception information.
4926 * Invokes the method represented by \p method on the object \p obj.
4928 * \p obj is the \c this pointer, it should be NULL for static
4929 * methods, a \c MonoObject* for object instances and a pointer to
4930 * the value type for value types.
4932 * The \p params array contains the arguments to the method with the
4933 * same convention: \c MonoObject* pointers for object instances and
4934 * pointers to the value type otherwise. The \c _invoke_array
4935 * variant takes a C# \c object[] as the params argument (\c MonoArray*):
4936 * in this case the value types are boxed inside the
4937 * respective reference representation.
4939 * From unmanaged code you'll usually use the
4940 * mono_runtime_invoke_checked() variant.
4942 * Note that this function doesn't handle virtual methods for
4943 * you, it will exec the exact method you pass: we still need to
4944 * expose a function to lookup the derived class implementation
4945 * of a virtual method (there are examples of this in the code,
4948 * You can pass NULL as the \p exc argument if you don't want to
4949 * catch exceptions, otherwise, \c *exc will be set to the exception
4950 * thrown, if any. if an exception is thrown, you can't use the
4951 * \c MonoObject* result from the function.
4953 * If the method returns a value type, it is boxed in an object
4957 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4962 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, exc, &error);
4964 mono_error_cleanup (&error);
4967 if (!is_ok (&error))
4968 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
4972 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, NULL, &error);
4973 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
4979 * mono_runtime_invoke_array_checked:
4980 * \param method method to invoke
4981 * \param obj object instance
4982 * \param params arguments to the method
4983 * \param error set on failure.
4984 * Invokes the method represented by \p method on the object \p obj.
4986 * \p obj is the \c this pointer, it should be NULL for static
4987 * methods, a \c MonoObject* for object instances and a pointer to
4988 * the value type for value types.
4990 * The \p params array contains the arguments to the method with the
4991 * same convention: \c MonoObject* pointers for object instances and
4992 * pointers to the value type otherwise. The \c _invoke_array
4993 * variant takes a C# \c object[] as the \p params argument (\c MonoArray*):
4994 * in this case the value types are boxed inside the
4995 * respective reference representation.
4997 * From unmanaged code you'll usually use the
4998 * mono_runtime_invoke_checked() variant.
5000 * Note that this function doesn't handle virtual methods for
5001 * you, it will exec the exact method you pass: we still need to
5002 * expose a function to lookup the derived class implementation
5003 * of a virtual method (there are examples of this in the code,
5006 * On failure or exception, \p error will be set. In that case, you
5007 * can't use the \c MonoObject* result from the function.
5009 * If the method returns a value type, it is boxed in an object
5013 mono_runtime_invoke_array_checked (MonoMethod *method, void *obj, MonoArray *params,
5017 return mono_runtime_try_invoke_array (method, obj, params, NULL, error);
5021 * mono_runtime_try_invoke_array:
5022 * \param method method to invoke
5023 * \param obj object instance
5024 * \param params arguments to the method
5025 * \param exc exception information.
5026 * \param error set on failure.
5027 * Invokes the method represented by \p method on the object \p obj.
5029 * \p obj is the \c this pointer, it should be NULL for static
5030 * methods, a \c MonoObject* for object instances and a pointer to
5031 * the value type for value types.
5033 * The \p params array contains the arguments to the method with the
5034 * same convention: \c MonoObject* pointers for object instances and
5035 * pointers to the value type otherwise. The \c _invoke_array
5036 * variant takes a C# \c object[] as the params argument (\c MonoArray*):
5037 * in this case the value types are boxed inside the
5038 * respective reference representation.
5040 * From unmanaged code you'll usually use the
5041 * mono_runtime_invoke_checked() variant.
5043 * Note that this function doesn't handle virtual methods for
5044 * you, it will exec the exact method you pass: we still need to
5045 * expose a function to lookup the derived class implementation
5046 * of a virtual method (there are examples of this in the code,
5049 * You can pass NULL as the \p exc argument if you don't want to catch
5050 * exceptions, otherwise, \c *exc will be set to the exception thrown, if
5051 * any. On other failures, \p error will be set. If an exception is
5052 * thrown or there's an error, you can't use the \c MonoObject* result
5053 * from the function.
5055 * If the method returns a value type, it is boxed in an object
5059 mono_runtime_try_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
5060 MonoObject **exc, MonoError *error)
5062 MONO_REQ_GC_UNSAFE_MODE;
5066 MonoMethodSignature *sig = mono_method_signature (method);
5067 gpointer *pa = NULL;
5070 gboolean has_byref_nullables = FALSE;
5072 if (NULL != params) {
5073 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
5074 for (i = 0; i < mono_array_length (params); i++) {
5075 MonoType *t = sig->params [i];
5076 pa [i] = invoke_array_extract_argument (params, i, t, &has_byref_nullables, error);
5077 return_val_if_nok (error, NULL);
5081 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
5084 if (mono_class_is_nullable (method->klass)) {
5085 /* Need to create a boxed vtype instead */
5091 return mono_value_box_checked (mono_domain_get (), method->klass->cast_class, pa [0], error);
5096 obj = mono_object_new_checked (mono_domain_get (), method->klass, error);
5097 mono_error_assert_ok (error);
5098 g_assert (obj); /*maybe we should raise a TLE instead?*/
5099 #ifndef DISABLE_REMOTING
5100 if (mono_object_is_transparent_proxy (obj)) {
5101 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
5104 if (method->klass->valuetype)
5105 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
5108 } else if (method->klass->valuetype) {
5109 obj = mono_value_box_checked (mono_domain_get (), method->klass, obj, error);
5110 return_val_if_nok (error, NULL);
5114 mono_runtime_try_invoke (method, o, pa, exc, error);
5116 mono_runtime_invoke_checked (method, o, pa, error);
5119 return (MonoObject *)obj;
5121 if (mono_class_is_nullable (method->klass)) {
5122 MonoObject *nullable;
5124 /* Convert the unboxed vtype into a Nullable structure */
5125 nullable = mono_object_new_checked (mono_domain_get (), method->klass, error);
5126 return_val_if_nok (error, NULL);
5128 MonoObject *boxed = mono_value_box_checked (mono_domain_get (), method->klass->cast_class, obj, error);
5129 return_val_if_nok (error, NULL);
5130 mono_nullable_init ((guint8 *)mono_object_unbox (nullable), boxed, method->klass);
5131 obj = mono_object_unbox (nullable);
5134 /* obj must be already unboxed if needed */
5136 res = mono_runtime_try_invoke (method, obj, pa, exc, error);
5138 res = mono_runtime_invoke_checked (method, obj, pa, error);
5140 return_val_if_nok (error, NULL);
5142 if (sig->ret->type == MONO_TYPE_PTR) {
5143 MonoClass *pointer_class;
5144 static MonoMethod *box_method;
5146 MonoObject *box_exc;
5149 * The runtime-invoke wrapper returns a boxed IntPtr, need to
5150 * convert it to a Pointer object.
5152 pointer_class = mono_class_get_pointer_class ();
5154 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
5156 g_assert (res->vtable->klass == mono_defaults.int_class);
5157 box_args [0] = ((MonoIntPtr*)res)->m_value;
5158 box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, error);
5159 return_val_if_nok (error, NULL);
5161 res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, error);
5162 g_assert (box_exc == NULL);
5163 mono_error_assert_ok (error);
5166 if (has_byref_nullables) {
5168 * The runtime invoke wrapper already converted byref nullables back,
5169 * and stored them in pa, we just need to copy them back to the
5172 for (i = 0; i < mono_array_length (params); i++) {
5173 MonoType *t = sig->params [i];
5175 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
5176 mono_array_setref (params, i, pa [i]);
5186 * \param klass the class of the object that we want to create
5187 * \returns a newly created object whose definition is
5188 * looked up using \p klass. This will not invoke any constructors,
5189 * so the consumer of this routine has to invoke any constructors on
5190 * its own to initialize the object.
5192 * It returns NULL on failure.
5195 mono_object_new (MonoDomain *domain, MonoClass *klass)
5197 MONO_REQ_GC_UNSAFE_MODE;
5201 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5203 mono_error_cleanup (&error);
5208 ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
5210 MONO_REQ_GC_UNSAFE_MODE;
5214 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5216 mono_error_set_pending_exception (&error);
5221 * mono_object_new_checked:
5222 * \param klass the class of the object that we want to create
5223 * \param error set on error
5224 * \returns a newly created object whose definition is
5225 * looked up using \p klass. This will not invoke any constructors,
5226 * so the consumer of this routine has to invoke any constructors on
5227 * its own to initialize the object.
5229 * It returns NULL on failure and sets \p error.
5232 mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
5234 MONO_REQ_GC_UNSAFE_MODE;
5238 vtable = mono_class_vtable (domain, klass);
5239 g_assert (vtable); /* FIXME don't swallow the error */
5241 MonoObject *o = mono_object_new_specific_checked (vtable, error);
5246 * mono_object_new_pinned:
5248 * Same as mono_object_new, but the returned object will be pinned.
5249 * For SGEN, these objects will only be freed at appdomain unload.
5252 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
5254 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 = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
5265 if (G_UNLIKELY (!o))
5266 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
5267 else if (G_UNLIKELY (vtable->klass->has_finalize))
5268 mono_object_register_finalizer (o);
5274 * mono_object_new_specific:
5275 * \param vtable the vtable of the object that we want to create
5276 * \returns A newly created object with class and domain specified
5280 mono_object_new_specific (MonoVTable *vtable)
5283 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5284 mono_error_cleanup (&error);
5290 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
5292 MONO_REQ_GC_UNSAFE_MODE;
5298 /* check for is_com_object for COM Interop */
5299 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
5302 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
5305 MonoClass *klass = mono_class_get_activation_services_class ();
5308 mono_class_init (klass);
5310 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
5312 mono_error_set_not_supported (error, "Linked away.");
5315 vtable->domain->create_proxy_for_type_method = im;
5318 pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
5319 if (!mono_error_ok (error))
5322 o = mono_runtime_invoke_checked (im, NULL, pa, error);
5323 if (!mono_error_ok (error))
5330 return mono_object_new_alloc_specific_checked (vtable, error);
5334 ves_icall_object_new_specific (MonoVTable *vtable)
5337 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5338 mono_error_set_pending_exception (&error);
5344 * mono_object_new_alloc_specific:
5345 * \param vtable virtual table for the object.
5346 * This function allocates a new \c MonoObject with the type derived
5347 * from the \p vtable information. If the class of this object has a
5348 * finalizer, then the object will be tracked for finalization.
5350 * This method might raise an exception on errors. Use the
5351 * \c mono_object_new_fast_checked method if you want to manually raise
5354 * \returns the allocated object.
5357 mono_object_new_alloc_specific (MonoVTable *vtable)
5360 MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
5361 mono_error_cleanup (&error);
5367 * mono_object_new_alloc_specific_checked:
5368 * \param vtable virtual table for the object.
5369 * \param error holds the error return value.
5371 * This function allocates a new \c MonoObject with the type derived
5372 * from the \p vtable information. If the class of this object has a
5373 * finalizer, then the object will be tracked for finalization.
5375 * If there is not enough memory, the \p error parameter will be set
5376 * and will contain a user-visible message with the amount of bytes
5377 * that were requested.
5379 * \returns the allocated object, or NULL if there is not enough memory
5382 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
5384 MONO_REQ_GC_UNSAFE_MODE;
5390 o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5392 if (G_UNLIKELY (!o))
5393 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5394 else if (G_UNLIKELY (vtable->klass->has_finalize))
5395 mono_object_register_finalizer (o);
5401 * mono_object_new_fast:
5402 * \param vtable virtual table for the object.
5404 * This function allocates a new \c MonoObject with the type derived
5405 * from the \p vtable information. The returned object is not tracked
5406 * for finalization. If your object implements a finalizer, you should
5407 * use \c mono_object_new_alloc_specific instead.
5409 * This method might raise an exception on errors. Use the
5410 * \c mono_object_new_fast_checked method if you want to manually raise
5413 * \returns the allocated object.
5416 mono_object_new_fast (MonoVTable *vtable)
5419 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5420 mono_error_cleanup (&error);
5426 * mono_object_new_fast_checked:
5427 * \param vtable virtual table for the object.
5428 * \param error holds the error return value.
5430 * This function allocates a new \c MonoObject with the type derived
5431 * from the \p vtable information. The returned object is not tracked
5432 * for finalization. If your object implements a finalizer, you should
5433 * use \c mono_object_new_alloc_specific_checked instead.
5435 * If there is not enough memory, the \p error parameter will be set
5436 * and will contain a user-visible message with the amount of bytes
5437 * that were requested.
5439 * \returns the allocated object, or NULL if there is not enough memory
5442 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
5444 MONO_REQ_GC_UNSAFE_MODE;
5450 o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5452 if (G_UNLIKELY (!o))
5453 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5459 ves_icall_object_new_fast (MonoVTable *vtable)
5462 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5463 mono_error_set_pending_exception (&error);
5469 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
5471 MONO_REQ_GC_UNSAFE_MODE;
5477 o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
5479 if (G_UNLIKELY (!o))
5480 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5481 else if (G_UNLIKELY (vtable->klass->has_finalize))
5482 mono_object_register_finalizer (o);
5488 * mono_class_get_allocation_ftn:
5489 * \param vtable vtable
5490 * \param for_box the object will be used for boxing
5491 * \param pass_size_in_words Unused
5492 * \returns the allocation function appropriate for the given class.
5495 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
5497 MONO_REQ_GC_NEUTRAL_MODE;
5499 *pass_size_in_words = FALSE;
5501 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass))
5502 return ves_icall_object_new_specific;
5504 if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
5506 return ves_icall_object_new_fast;
5509 * FIXME: This is actually slower than ves_icall_object_new_fast, because
5510 * of the overhead of parameter passing.
5513 *pass_size_in_words = TRUE;
5514 #ifdef GC_REDIRECT_TO_LOCAL
5515 return GC_local_gcj_fast_malloc;
5517 return GC_gcj_fast_malloc;
5522 return ves_icall_object_new_specific;
5526 * mono_object_new_from_token:
5527 * \param image Context where the type_token is hosted
5528 * \param token a token of the type that we want to create
5529 * \returns A newly created object whose definition is
5530 * looked up using \p token in the \p image image
5533 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
5535 MONO_REQ_GC_UNSAFE_MODE;
5541 klass = mono_class_get_checked (image, token, &error);
5542 mono_error_assert_ok (&error);
5544 result = mono_object_new_checked (domain, klass, &error);
5546 mono_error_cleanup (&error);
5553 * mono_object_clone:
5554 * \param obj the object to clone
5555 * \returns A newly created object who is a shallow copy of \p obj
5558 mono_object_clone (MonoObject *obj)
5561 MonoObject *o = mono_object_clone_checked (obj, &error);
5562 mono_error_cleanup (&error);
5568 mono_object_clone_checked (MonoObject *obj, MonoError *error)
5570 MONO_REQ_GC_UNSAFE_MODE;
5577 size = obj->vtable->klass->instance_size;
5579 if (obj->vtable->klass->rank)
5580 return (MonoObject*)mono_array_clone_checked ((MonoArray*)obj, error);
5582 o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
5584 if (G_UNLIKELY (!o)) {
5585 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5589 /* If the object doesn't contain references this will do a simple memmove. */
5590 mono_gc_wbarrier_object_copy (o, obj);
5592 if (obj->vtable->klass->has_finalize)
5593 mono_object_register_finalizer (o);
5598 * mono_array_full_copy:
5599 * \param src source array to copy
5600 * \param dest destination array
5601 * Copies the content of one array to another with exactly the same type and size.
5604 mono_array_full_copy (MonoArray *src, MonoArray *dest)
5606 MONO_REQ_GC_UNSAFE_MODE;
5609 MonoClass *klass = src->obj.vtable->klass;
5611 g_assert (klass == dest->obj.vtable->klass);
5613 size = mono_array_length (src);
5614 g_assert (size == mono_array_length (dest));
5615 size *= mono_array_element_size (klass);
5617 array_full_copy_unchecked_size (src, dest, klass, size);
5621 array_full_copy_unchecked_size (MonoArray *src, MonoArray *dest, MonoClass *klass, uintptr_t size)
5624 if (klass->element_class->valuetype) {
5625 if (klass->element_class->has_references)
5626 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
5628 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5630 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
5633 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5638 * mono_array_clone_in_domain:
5639 * \param domain the domain in which the array will be cloned into
5640 * \param array the array to clone
5641 * \param error set on error
5642 * This routine returns a copy of the array that is hosted on the
5643 * specified \c MonoDomain. On failure returns NULL and sets \p error.
5646 mono_array_clone_in_domain (MonoDomain *domain, MonoArrayHandle array_handle, MonoError *error)
5648 MONO_REQ_GC_UNSAFE_MODE;
5650 MonoArrayHandle result = MONO_HANDLE_NEW (MonoArray, NULL);
5652 MonoClass *klass = mono_handle_class (array_handle);
5656 /* Pin source array here - if bounds is non-NULL, it's a pointer into the object data */
5657 uint32_t src_handle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, array_handle), TRUE);
5659 MonoArrayBounds *array_bounds = MONO_HANDLE_GETVAL (array_handle, bounds);
5661 if (array_bounds == NULL) {
5662 size = mono_array_handle_length (array_handle);
5663 o = mono_array_new_full_handle (domain, klass, &size, NULL, error);
5666 size *= mono_array_element_size (klass);
5668 uintptr_t *sizes = (uintptr_t *)alloca (klass->rank * sizeof (uintptr_t));
5669 intptr_t *lower_bounds = (intptr_t *)alloca (klass->rank * sizeof (intptr_t));
5670 size = mono_array_element_size (klass);
5671 for (int i = 0; i < klass->rank; ++i) {
5672 sizes [i] = array_bounds [i].length;
5673 size *= array_bounds [i].length;
5674 lower_bounds [i] = array_bounds [i].lower_bound;
5676 o = mono_array_new_full_handle (domain, klass, sizes, lower_bounds, error);
5681 uint32_t dst_handle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, o), TRUE);
5682 array_full_copy_unchecked_size (MONO_HANDLE_RAW (array_handle), MONO_HANDLE_RAW (o), klass, size);
5683 mono_gchandle_free (dst_handle);
5685 MONO_HANDLE_ASSIGN (result, o);
5688 mono_gchandle_free (src_handle);
5694 * \param array the array to clone
5695 * \returns A newly created array who is a shallow copy of \p array
5698 mono_array_clone (MonoArray *array)
5700 MONO_REQ_GC_UNSAFE_MODE;
5703 MonoArray *result = mono_array_clone_checked (array, &error);
5704 mono_error_cleanup (&error);
5709 * mono_array_clone_checked:
5710 * \param array the array to clone
5711 * \param error set on error
5712 * \returns A newly created array who is a shallow copy of \p array. On
5713 * failure returns NULL and sets \p error.
5716 mono_array_clone_checked (MonoArray *array_raw, MonoError *error)
5718 MONO_REQ_GC_UNSAFE_MODE;
5719 HANDLE_FUNCTION_ENTER ();
5720 /* FIXME: callers of mono_array_clone_checked should use handles */
5722 MONO_HANDLE_DCL (MonoArray, array);
5723 MonoArrayHandle result = mono_array_clone_in_domain (MONO_HANDLE_DOMAIN (array), array, error);
5724 HANDLE_FUNCTION_RETURN_OBJ (result);
5727 /* helper macros to check for overflow when calculating the size of arrays */
5728 #ifdef MONO_BIG_ARRAYS
5729 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
5730 #define MYGUINT_MAX MYGUINT64_MAX
5731 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5732 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
5733 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5734 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
5735 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
5737 #define MYGUINT32_MAX 4294967295U
5738 #define MYGUINT_MAX MYGUINT32_MAX
5739 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5740 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
5741 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5742 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
5743 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
5747 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
5749 MONO_REQ_GC_NEUTRAL_MODE;
5753 byte_len = mono_array_element_size (klass);
5754 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
5757 if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
5759 byte_len += MONO_SIZEOF_MONO_ARRAY;
5767 * mono_array_new_full:
5768 * \param domain domain where the object is created
5769 * \param array_class array class
5770 * \param lengths lengths for each dimension in the array
5771 * \param lower_bounds lower bounds for each dimension in the array (may be NULL)
5772 * This routine creates a new array object with the given dimensions,
5773 * lower bounds and type.
5776 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
5779 MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
5780 mono_error_cleanup (&error);
5786 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
5788 MONO_REQ_GC_UNSAFE_MODE;
5790 uintptr_t byte_len = 0, len, bounds_size;
5793 MonoArrayBounds *bounds;
5799 if (!array_class->inited)
5800 mono_class_init (array_class);
5804 /* A single dimensional array with a 0 lower bound is the same as an szarray */
5805 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
5807 if (len > MONO_ARRAY_MAX_INDEX) {
5808 mono_error_set_generic_error (error, "System", "OverflowException", "");
5813 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
5815 for (i = 0; i < array_class->rank; ++i) {
5816 if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
5817 mono_error_set_generic_error (error, "System", "OverflowException", "");
5820 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5821 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5828 if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5829 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5835 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5836 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5839 byte_len = (byte_len + 3) & ~3;
5840 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5841 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5844 byte_len += bounds_size;
5847 * Following three lines almost taken from mono_object_new ():
5848 * they need to be kept in sync.
5850 vtable = mono_class_vtable_full (domain, array_class, error);
5851 return_val_if_nok (error, NULL);
5854 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5856 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5858 if (G_UNLIKELY (!o)) {
5859 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5863 array = (MonoArray*)o;
5865 bounds = array->bounds;
5868 for (i = 0; i < array_class->rank; ++i) {
5869 bounds [i].length = lengths [i];
5871 bounds [i].lower_bound = lower_bounds [i];
5880 * \param domain domain where the object is created
5881 * \param eclass element class
5882 * \param n number of array elements
5883 * This routine creates a new szarray with \p n elements of type \p eclass.
5886 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5888 MONO_REQ_GC_UNSAFE_MODE;
5891 MonoArray *result = mono_array_new_checked (domain, eclass, n, &error);
5892 mono_error_cleanup (&error);
5897 * mono_array_new_checked:
5898 * \param domain domain where the object is created
5899 * \param eclass element class
5900 * \param n number of array elements
5901 * \param error set on error
5902 * This routine creates a new szarray with \p n elements of type \p eclass.
5903 * On failure returns NULL and sets \p error.
5906 mono_array_new_checked (MonoDomain *domain, MonoClass *eclass, uintptr_t n, MonoError *error)
5912 ac = mono_array_class_get (eclass, 1);
5915 MonoVTable *vtable = mono_class_vtable_full (domain, ac, error);
5916 return_val_if_nok (error, NULL);
5918 return mono_array_new_specific_checked (vtable, n, error);
5922 ves_icall_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5925 MonoArray *arr = mono_array_new_checked (domain, eclass, n, &error);
5926 mono_error_set_pending_exception (&error);
5932 * mono_array_new_specific:
5933 * \param vtable a vtable in the appropriate domain for an initialized class
5934 * \param n number of array elements
5935 * This routine is a fast alternative to \c mono_array_new for code which
5936 * can be sure about the domain it operates in.
5939 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5942 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5943 mono_error_cleanup (&error);
5949 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
5951 MONO_REQ_GC_UNSAFE_MODE;
5958 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
5959 mono_error_set_generic_error (error, "System", "OverflowException", "");
5963 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
5964 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5967 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
5969 if (G_UNLIKELY (!o)) {
5970 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5974 return (MonoArray*)o;
5978 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
5981 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5982 mono_error_set_pending_exception (&error);
5988 * mono_string_empty_wrapper:
5990 * Returns: The same empty string instance as the managed string.Empty
5993 mono_string_empty_wrapper (void)
5995 MonoDomain *domain = mono_domain_get ();
5996 return mono_string_empty (domain);
6000 * mono_string_empty:
6002 * Returns: The same empty string instance as the managed string.Empty
6005 mono_string_empty (MonoDomain *domain)
6008 g_assert (domain->empty_string);
6009 return domain->empty_string;
6013 * mono_string_new_utf16:
6014 * \param text a pointer to an utf16 string
6015 * \param len the length of the string
6016 * \returns A newly created string object which contains \p text.
6019 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
6021 MONO_REQ_GC_UNSAFE_MODE;
6024 MonoString *res = NULL;
6025 res = mono_string_new_utf16_checked (domain, text, len, &error);
6026 mono_error_cleanup (&error);
6032 * mono_string_new_utf16_checked:
6033 * \param text a pointer to an utf16 string
6034 * \param len the length of the string
6035 * \param error written on error.
6036 * \returns A newly created string object which contains \p text.
6037 * On error, returns NULL and sets \p error.
6040 mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
6042 MONO_REQ_GC_UNSAFE_MODE;
6048 s = mono_string_new_size_checked (domain, len, error);
6050 memcpy (mono_string_chars (s), text, len * 2);
6056 * mono_string_new_utf16_handle:
6057 * \param text a pointer to an utf16 string
6058 * \param len the length of the string
6059 * \param error written on error.
6060 * \returns A newly created string object which contains \p text.
6061 * On error, returns NULL and sets \p error.
6064 mono_string_new_utf16_handle (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
6066 return MONO_HANDLE_NEW (MonoString, mono_string_new_utf16_checked (domain, text, len, error));
6070 * mono_string_new_utf32_checked:
6071 * \param text a pointer to an utf32 string
6072 * \param len the length of the string
6073 * \param error set on failure.
6074 * \returns A newly created string object which contains \p text. On failure returns NULL and sets \p error.
6077 mono_string_new_utf32_checked (MonoDomain *domain, const mono_unichar4 *text, gint32 len, MonoError *error)
6079 MONO_REQ_GC_UNSAFE_MODE;
6082 mono_unichar2 *utf16_output = NULL;
6083 gint32 utf16_len = 0;
6084 GError *gerror = NULL;
6085 glong items_written;
6088 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
6091 g_error_free (gerror);
6093 while (utf16_output [utf16_len]) utf16_len++;
6095 s = mono_string_new_size_checked (domain, utf16_len, error);
6096 return_val_if_nok (error, NULL);
6098 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
6100 g_free (utf16_output);
6106 * mono_string_new_utf32:
6107 * \param text a pointer to a UTF-32 string
6108 * \param len the length of the string
6109 * \returns A newly created string object which contains \p text.
6112 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
6115 MonoString *result = mono_string_new_utf32_checked (domain, text, len, &error);
6116 mono_error_cleanup (&error);
6121 * mono_string_new_size:
6122 * \param text a pointer to a UTF-16 string
6123 * \param len the length of the string
6124 * \returns A newly created string object of \p len
6127 mono_string_new_size (MonoDomain *domain, gint32 len)
6130 MonoString *str = mono_string_new_size_checked (domain, len, &error);
6131 mono_error_cleanup (&error);
6137 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
6139 MONO_REQ_GC_UNSAFE_MODE;
6147 /* check for overflow */
6148 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
6149 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
6153 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
6154 g_assert (size > 0);
6156 vtable = mono_class_vtable (domain, mono_defaults.string_class);
6159 s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
6161 if (G_UNLIKELY (!s)) {
6162 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", size);
6170 * mono_string_new_len:
6171 * \param text a pointer to an utf8 string
6172 * \param length number of bytes in \p text to consider
6173 * \returns A newly created string object which contains \p text.
6176 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
6178 MONO_REQ_GC_UNSAFE_MODE;
6181 MonoString *result = mono_string_new_len_checked (domain, text, length, &error);
6182 mono_error_cleanup (&error);
6187 * mono_string_new_len_checked:
6188 * \param text a pointer to an utf8 string
6189 * \param length number of bytes in \p text to consider
6190 * \param error set on error
6191 * \returns A newly created string object which contains \p text. On
6192 * failure returns NULL and sets \p error.
6195 mono_string_new_len_checked (MonoDomain *domain, const char *text, guint length, MonoError *error)
6197 MONO_REQ_GC_UNSAFE_MODE;
6201 GError *eg_error = NULL;
6202 MonoString *o = NULL;
6204 glong items_written;
6206 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
6209 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6211 g_error_free (eg_error);
6220 * \param text a pointer to a UTF-8 string
6221 * \deprecated Use \c mono_string_new_checked in new code.
6222 * This function asserts if it cannot allocate a new string.
6223 * \returns A newly created string object which contains \p text.
6226 mono_string_new (MonoDomain *domain, const char *text)
6229 MonoString *res = NULL;
6230 res = mono_string_new_checked (domain, text, &error);
6231 mono_error_assert_ok (&error);
6236 * mono_string_new_checked:
6237 * \param text a pointer to an utf8 string
6238 * \param merror set on error
6239 * \returns A newly created string object which contains \p text.
6240 * On error returns NULL and sets \p merror.
6243 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
6245 MONO_REQ_GC_UNSAFE_MODE;
6247 GError *eg_error = NULL;
6248 MonoString *o = NULL;
6250 glong items_written;
6257 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &eg_error);
6260 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6262 mono_error_set_execution_engine (error, "String conversion error: %s", eg_error->message);
6267 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
6272 MonoString *o = NULL;
6274 if (!g_utf8_validate (text, -1, &end)) {
6275 mono_error_set_argument (error, "text", "Not a valid utf8 string");
6279 len = g_utf8_strlen (text, -1);
6280 o = mono_string_new_size_checked (domain, len, error);
6283 str = mono_string_chars (o);
6285 while (text < end) {
6286 *str++ = g_utf8_get_char (text);
6287 text = g_utf8_next_char (text);
6296 * mono_string_new_wrapper:
6297 * \param text pointer to UTF-8 characters.
6298 * Helper function to create a string object from \p text in the current domain.
6301 mono_string_new_wrapper (const char *text)
6303 MONO_REQ_GC_UNSAFE_MODE;
6305 MonoDomain *domain = mono_domain_get ();
6309 MonoString *result = mono_string_new_checked (domain, text, &error);
6310 mono_error_assert_ok (&error);
6319 * \param class the class of the value
6320 * \param value a pointer to the unboxed data
6321 * \returns A newly created object which contains \p value.
6324 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
6327 MonoObject *result = mono_value_box_checked (domain, klass, value, &error);
6328 mono_error_cleanup (&error);
6333 * mono_value_box_checked:
6334 * \param domain the domain of the new object
6335 * \param class the class of the value
6336 * \param value a pointer to the unboxed data
6337 * \param error set on error
6338 * \returns A newly created object which contains \p value. On failure
6339 * returns NULL and sets \p error.
6342 mono_value_box_checked (MonoDomain *domain, MonoClass *klass, gpointer value, MonoError *error)
6344 MONO_REQ_GC_UNSAFE_MODE;
6351 g_assert (klass->valuetype);
6352 if (mono_class_is_nullable (klass))
6353 return mono_nullable_box ((guint8 *)value, klass, error);
6355 vtable = mono_class_vtable (domain, klass);
6358 size = mono_class_instance_size (klass);
6359 res = mono_object_new_alloc_specific_checked (vtable, error);
6360 return_val_if_nok (error, NULL);
6362 size = size - sizeof (MonoObject);
6365 g_assert (size == mono_class_value_size (klass, NULL));
6366 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
6368 #if NO_UNALIGNED_ACCESS
6369 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6373 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
6376 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
6379 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
6382 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
6385 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6389 if (klass->has_finalize) {
6390 mono_object_register_finalizer (res);
6391 return_val_if_nok (error, NULL);
6398 * \param dest destination pointer
6399 * \param src source pointer
6400 * \param klass a valuetype class
6401 * Copy a valuetype from \p src to \p dest. This function must be used
6402 * when \p klass contains reference fields.
6405 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
6407 MONO_REQ_GC_UNSAFE_MODE;
6409 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
6413 * mono_value_copy_array:
6414 * \param dest destination array
6415 * \param dest_idx index in the \p dest array
6416 * \param src source pointer
6417 * \param count number of items
6418 * Copy \p count valuetype items from \p src to the array \p dest at index \p dest_idx.
6419 * This function must be used when \p klass contains references fields.
6420 * Overlap is handled.
6423 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
6425 MONO_REQ_GC_UNSAFE_MODE;
6427 int size = mono_array_element_size (dest->obj.vtable->klass);
6428 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
6429 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
6430 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
6434 * mono_object_get_domain:
6435 * \param obj object to query
6436 * \returns the \c MonoDomain where the object is hosted
6439 mono_object_get_domain (MonoObject *obj)
6441 MONO_REQ_GC_UNSAFE_MODE;
6443 return mono_object_domain (obj);
6447 * mono_object_get_class:
6448 * \param obj object to query
6449 * Use this function to obtain the \c MonoClass* for a given \c MonoObject.
6450 * \returns the \c MonoClass of the object.
6453 mono_object_get_class (MonoObject *obj)
6455 MONO_REQ_GC_UNSAFE_MODE;
6457 return mono_object_class (obj);
6460 * mono_object_get_size:
6461 * \param o object to query
6462 * \returns the size, in bytes, of \p o
6465 mono_object_get_size (MonoObject* o)
6467 MONO_REQ_GC_UNSAFE_MODE;
6469 MonoClass* klass = mono_object_class (o);
6470 if (klass == mono_defaults.string_class) {
6471 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
6472 } else if (o->vtable->rank) {
6473 MonoArray *array = (MonoArray*)o;
6474 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
6475 if (array->bounds) {
6478 size += sizeof (MonoArrayBounds) * o->vtable->rank;
6482 return mono_class_instance_size (klass);
6487 * mono_object_unbox:
6488 * \param obj object to unbox
6489 * \returns a pointer to the start of the valuetype boxed in this
6492 * This method will assert if the object passed is not a valuetype.
6495 mono_object_unbox (MonoObject *obj)
6497 MONO_REQ_GC_UNSAFE_MODE;
6499 /* add assert for valuetypes? */
6500 g_assert (obj->vtable->klass->valuetype);
6501 return ((char*)obj) + sizeof (MonoObject);
6505 * mono_object_isinst:
6506 * \param obj an object
6507 * \param klass a pointer to a class
6508 * \returns \p obj if \p obj is derived from \p klass or NULL otherwise.
6511 mono_object_isinst (MonoObject *obj_raw, MonoClass *klass)
6513 MONO_REQ_GC_UNSAFE_MODE;
6515 HANDLE_FUNCTION_ENTER ();
6516 MONO_HANDLE_DCL (MonoObject, obj);
6518 MonoObjectHandle result = mono_object_handle_isinst (obj, klass, &error);
6519 mono_error_cleanup (&error);
6520 HANDLE_FUNCTION_RETURN_OBJ (result);
6525 * mono_object_isinst_checked:
6526 * \param obj an object
6527 * \param klass a pointer to a class
6528 * \param error set on error
6529 * \returns \p obj if \p obj is derived from \p klass or NULL if it isn't.
6530 * On failure returns NULL and sets \p error.
6533 mono_object_isinst_checked (MonoObject *obj_raw, MonoClass *klass, MonoError *error)
6535 MONO_REQ_GC_UNSAFE_MODE;
6537 HANDLE_FUNCTION_ENTER ();
6539 MONO_HANDLE_DCL (MonoObject, obj);
6540 MonoObjectHandle result = mono_object_handle_isinst (obj, klass, error);
6541 HANDLE_FUNCTION_RETURN_OBJ (result);
6545 * mono_object_handle_isinst:
6546 * \param obj an object
6547 * \param klass a pointer to a class
6548 * \param error set on error
6549 * \returns \p obj if \p obj is derived from \p klass or NULL if it isn't.
6550 * On failure returns NULL and sets \p error.
6553 mono_object_handle_isinst (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
6558 mono_class_init (klass);
6560 if (mono_class_is_marshalbyref (klass) || mono_class_is_interface (klass)) {
6561 return mono_object_handle_isinst_mbyref (obj, klass, error);
6564 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6566 if (!MONO_HANDLE_IS_NULL (obj) && mono_class_is_assignable_from (klass, mono_handle_class (obj)))
6567 MONO_HANDLE_ASSIGN (result, obj);
6572 * mono_object_isinst_mbyref:
6575 mono_object_isinst_mbyref (MonoObject *obj_raw, MonoClass *klass)
6577 MONO_REQ_GC_UNSAFE_MODE;
6579 HANDLE_FUNCTION_ENTER ();
6581 MONO_HANDLE_DCL (MonoObject, obj);
6582 MonoObjectHandle result = mono_object_handle_isinst_mbyref (obj, klass, &error);
6583 mono_error_cleanup (&error); /* FIXME better API that doesn't swallow the error */
6584 HANDLE_FUNCTION_RETURN_OBJ (result);
6588 mono_object_handle_isinst_mbyref (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
6592 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6594 if (MONO_HANDLE_IS_NULL (obj))
6597 MonoVTable *vt = MONO_HANDLE_GETVAL (obj, vtable);
6599 if (mono_class_is_interface (klass)) {
6600 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
6601 MONO_HANDLE_ASSIGN (result, obj);
6605 /* casting an array one of the invariant interfaces that must act as such */
6606 if (klass->is_array_special_interface) {
6607 if (mono_class_is_assignable_from (klass, vt->klass)) {
6608 MONO_HANDLE_ASSIGN (result, obj);
6613 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
6614 else if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, mono_handle_class (obj))) {
6615 MONO_HANDLE_ASSIGN (result, obj);
6619 MonoClass *oklass = vt->klass;
6620 if (mono_class_is_transparent_proxy (oklass)){
6621 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), remote_class);
6622 oklass = remote_class->proxy_class;
6625 mono_class_setup_supertypes (klass);
6626 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass)) {
6627 MONO_HANDLE_ASSIGN (result, obj);
6631 #ifndef DISABLE_REMOTING
6632 if (mono_class_is_transparent_proxy (vt->klass))
6634 MonoBoolean custom_type_info = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), custom_type_info);
6635 if (!custom_type_info)
6637 MonoDomain *domain = mono_domain_get ();
6638 MonoObjectHandle rp = MONO_HANDLE_NEW (MonoObject, NULL);
6639 MONO_HANDLE_GET (rp, MONO_HANDLE_CAST (MonoTransparentProxy, obj), rp);
6640 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
6641 MonoMethod *im = NULL;
6644 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
6646 mono_error_set_not_supported (error, "Linked away.");
6649 im = mono_object_handle_get_virtual_method (rp, im, error);
6654 MonoReflectionTypeHandle reftype = mono_type_get_object_handle (domain, &klass->byval_arg, error);
6658 pa [0] = MONO_HANDLE_RAW (reftype);
6659 pa [1] = MONO_HANDLE_RAW (obj);
6660 MonoObject *res = mono_runtime_invoke_checked (im, MONO_HANDLE_RAW (rp), pa, error);
6664 if (*(MonoBoolean *) mono_object_unbox(res)) {
6665 /* Update the vtable of the remote type, so it can safely cast to this new type */
6666 mono_upgrade_remote_class (domain, obj, klass, error);
6669 MONO_HANDLE_ASSIGN (result, obj);
6672 #endif /* DISABLE_REMOTING */
6678 * mono_object_castclass_mbyref:
6679 * \param obj an object
6680 * \param klass a pointer to a class
6681 * \returns \p obj if \p obj is derived from \p klass, returns NULL otherwise.
6684 mono_object_castclass_mbyref (MonoObject *obj_raw, MonoClass *klass)
6686 MONO_REQ_GC_UNSAFE_MODE;
6687 HANDLE_FUNCTION_ENTER ();
6689 MONO_HANDLE_DCL (MonoObject, obj);
6690 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6691 if (MONO_HANDLE_IS_NULL (obj))
6693 MONO_HANDLE_ASSIGN (result, mono_object_handle_isinst_mbyref (obj, klass, &error));
6694 mono_error_cleanup (&error);
6696 HANDLE_FUNCTION_RETURN_OBJ (result);
6700 MonoDomain *orig_domain;
6706 str_lookup (MonoDomain *domain, gpointer user_data)
6708 MONO_REQ_GC_UNSAFE_MODE;
6710 LDStrInfo *info = (LDStrInfo *)user_data;
6711 if (info->res || domain == info->orig_domain)
6713 info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
6717 mono_string_get_pinned (MonoString *str, MonoError *error)
6719 MONO_REQ_GC_UNSAFE_MODE;
6723 /* We only need to make a pinned version of a string if this is a moving GC */
6724 if (!mono_gc_is_moving ())
6728 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
6729 news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
6731 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
6732 news->length = mono_string_length (str);
6734 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6740 mono_string_is_interned_lookup (MonoString *str, int insert, MonoError *error)
6742 MONO_REQ_GC_UNSAFE_MODE;
6744 MonoGHashTable *ldstr_table;
6745 MonoString *s, *res;
6750 domain = ((MonoObject *)str)->vtable->domain;
6751 ldstr_table = domain->ldstr_table;
6753 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6759 /* Allocate outside the lock */
6761 s = mono_string_get_pinned (str, error);
6762 return_val_if_nok (error, NULL);
6765 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6770 mono_g_hash_table_insert (ldstr_table, s, s);
6775 LDStrInfo ldstr_info;
6776 ldstr_info.orig_domain = domain;
6777 ldstr_info.ins = str;
6778 ldstr_info.res = NULL;
6780 mono_domain_foreach (str_lookup, &ldstr_info);
6781 if (ldstr_info.res) {
6783 * the string was already interned in some other domain:
6784 * intern it in the current one as well.
6786 mono_g_hash_table_insert (ldstr_table, str, str);
6796 * mono_string_is_interned:
6797 * \param o String to probe
6798 * \returns Whether the string has been interned.
6801 mono_string_is_interned (MonoString *o)
6804 MonoString *result = mono_string_is_interned_lookup (o, FALSE, &error);
6805 /* This function does not fail. */
6806 mono_error_assert_ok (&error);
6811 * mono_string_intern:
6812 * \param o String to intern
6813 * Interns the string passed.
6814 * \returns The interned string.
6817 mono_string_intern (MonoString *str)
6820 MonoString *result = mono_string_intern_checked (str, &error);
6821 mono_error_assert_ok (&error);
6826 * mono_string_intern_checked:
6827 * \param o String to intern
6828 * \param error set on error.
6829 * Interns the string passed.
6830 * \returns The interned string. On failure returns NULL and sets \p error
6833 mono_string_intern_checked (MonoString *str, MonoError *error)
6835 MONO_REQ_GC_UNSAFE_MODE;
6839 return mono_string_is_interned_lookup (str, TRUE, error);
6844 * \param domain the domain where the string will be used.
6845 * \param image a metadata context
6846 * \param idx index into the user string table.
6847 * Implementation for the \c ldstr opcode.
6848 * \returns a loaded string from the \p image / \p idx combination.
6851 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
6854 MonoString *result = mono_ldstr_checked (domain, image, idx, &error);
6855 mono_error_cleanup (&error);
6860 * mono_ldstr_checked:
6861 * \param domain the domain where the string will be used.
6862 * \param image a metadata context
6863 * \param idx index into the user string table.
6864 * \param error set on error.
6865 * Implementation for the \c ldstr opcode.
6866 * \returns A loaded string from the \p image / \p idx combination.
6867 * On failure returns NULL and sets \p error.
6870 mono_ldstr_checked (MonoDomain *domain, MonoImage *image, guint32 idx, MonoError *error)
6872 MONO_REQ_GC_UNSAFE_MODE;
6875 if (image->dynamic) {
6876 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL, error);
6879 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6880 return NULL; /*FIXME we should probably be raising an exception here*/
6881 MonoString *str = mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx), error);
6887 * mono_ldstr_metadata_sig
6888 * \param domain the domain for the string
6889 * \param sig the signature of a metadata string
6890 * \param error set on error
6891 * \returns a \c MonoString for a string stored in the metadata. On
6892 * failure returns NULL and sets \p error.
6895 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error)
6897 MONO_REQ_GC_UNSAFE_MODE;
6900 const char *str = sig;
6901 MonoString *o, *interned;
6904 len2 = mono_metadata_decode_blob_size (str, &str);
6907 o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, error);
6908 return_val_if_nok (error, NULL);
6909 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
6912 guint16 *p2 = (guint16*)mono_string_chars (o);
6913 for (i = 0; i < len2; ++i) {
6914 *p2 = GUINT16_FROM_LE (*p2);
6920 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6923 return interned; /* o will get garbage collected */
6925 o = mono_string_get_pinned (o, error);
6928 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6930 mono_g_hash_table_insert (domain->ldstr_table, o, o);
6942 * Same as mono_ldstr, but return a NULL terminated utf8 string instead
6946 mono_ldstr_utf8 (MonoImage *image, guint32 idx, MonoError *error)
6952 GError *gerror = NULL;
6956 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6957 return NULL; /*FIXME we should probably be raising an exception here*/
6958 str = mono_metadata_user_string (image, idx);
6960 len2 = mono_metadata_decode_blob_size (str, &str);
6963 as = g_utf16_to_utf8 ((guint16*)str, len2, NULL, &written, &gerror);
6965 mono_error_set_argument (error, "string", "%s", gerror->message);
6966 g_error_free (gerror);
6969 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6970 if (len2 > written) {
6971 /* allocate the total length and copy the part of the string that has been converted */
6972 char *as2 = (char *)g_malloc0 (len2);
6973 memcpy (as2, as, written);
6982 * mono_string_to_utf8:
6983 * \param s a \c System.String
6984 * \deprecated Use \c mono_string_to_utf8_checked to avoid having an exception arbitrarily raised.
6985 * \returns the UTF-8 representation for \p s.
6986 * The resulting buffer needs to be freed with \c mono_free().
6989 mono_string_to_utf8 (MonoString *s)
6991 MONO_REQ_GC_UNSAFE_MODE;
6994 char *result = mono_string_to_utf8_checked (s, &error);
6996 if (!is_ok (&error)) {
6997 mono_error_cleanup (&error);
7004 * mono_string_to_utf8_checked:
7005 * \param s a \c System.String
7006 * \param error a \c MonoError.
7007 * Converts a \c MonoString to its UTF-8 representation. May fail; check
7008 * \p error to determine whether the conversion was successful.
7009 * The resulting buffer should be freed with \c mono_free().
7012 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
7014 MONO_REQ_GC_UNSAFE_MODE;
7018 GError *gerror = NULL;
7026 return g_strdup ("");
7028 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
7030 mono_error_set_argument (error, "string", "%s", gerror->message);
7031 g_error_free (gerror);
7034 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
7035 if (s->length > written) {
7036 /* allocate the total length and copy the part of the string that has been converted */
7037 char *as2 = (char *)g_malloc0 (s->length);
7038 memcpy (as2, as, written);
7047 mono_string_handle_to_utf8 (MonoStringHandle s, MonoError *error)
7049 return mono_string_to_utf8_checked (MONO_HANDLE_RAW (s), error);
7053 * mono_string_to_utf8_ignore:
7054 * \param s a MonoString
7055 * Converts a \c MonoString to its UTF-8 representation. Will ignore
7056 * invalid surrogate pairs.
7057 * The resulting buffer should be freed with \c mono_free().
7060 mono_string_to_utf8_ignore (MonoString *s)
7062 MONO_REQ_GC_UNSAFE_MODE;
7071 return g_strdup ("");
7073 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
7075 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
7076 if (s->length > written) {
7077 /* allocate the total length and copy the part of the string that has been converted */
7078 char *as2 = (char *)g_malloc0 (s->length);
7079 memcpy (as2, as, written);
7088 * mono_string_to_utf8_image_ignore:
7089 * \param s a \c System.String
7090 * Same as \c mono_string_to_utf8_ignore, but allocate the string from the image mempool.
7093 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
7095 MONO_REQ_GC_UNSAFE_MODE;
7097 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
7101 * mono_string_to_utf8_mp_ignore:
7102 * \param s a \c System.String
7103 * Same as \c mono_string_to_utf8_ignore, but allocate the string from a mempool.
7106 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
7108 MONO_REQ_GC_UNSAFE_MODE;
7110 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
7115 * mono_string_to_utf16:
7116 * \param s a \c MonoString
7117 * \returns a null-terminated array of the UTF-16 chars
7118 * contained in \p s. The result must be freed with \c g_free().
7119 * This is a temporary helper until our string implementation
7120 * is reworked to always include the null-terminating char.
7123 mono_string_to_utf16 (MonoString *s)
7125 MONO_REQ_GC_UNSAFE_MODE;
7132 as = (char *)g_malloc ((s->length * 2) + 2);
7133 as [(s->length * 2)] = '\0';
7134 as [(s->length * 2) + 1] = '\0';
7137 return (gunichar2 *)(as);
7140 memcpy (as, mono_string_chars(s), s->length * 2);
7141 return (gunichar2 *)(as);
7145 * mono_string_to_utf32:
7146 * \param s a \c MonoString
7147 * \returns a null-terminated array of the UTF-32 (UCS-4) chars
7148 * contained in \p s. The result must be freed with \c g_free().
7151 mono_string_to_utf32 (MonoString *s)
7153 MONO_REQ_GC_UNSAFE_MODE;
7155 mono_unichar4 *utf32_output = NULL;
7156 GError *error = NULL;
7157 glong items_written;
7162 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
7165 g_error_free (error);
7167 return utf32_output;
7171 * mono_string_from_utf16:
7172 * \param data the UTF-16 string (LPWSTR) to convert
7173 * Converts a NULL-terminated UTF-16 string (LPWSTR) to a \c MonoString.
7174 * \returns a \c MonoString.
7177 mono_string_from_utf16 (gunichar2 *data)
7180 MonoString *result = mono_string_from_utf16_checked (data, &error);
7181 mono_error_cleanup (&error);
7186 * mono_string_from_utf16_checked:
7187 * \param data the UTF-16 string (LPWSTR) to convert
7188 * \param error set on error
7189 * Converts a NULL-terminated UTF-16 string (LPWSTR) to a \c MonoString.
7190 * \returns a \c MonoString. On failure sets \p error and returns NULL.
7193 mono_string_from_utf16_checked (gunichar2 *data, MonoError *error)
7196 MONO_REQ_GC_UNSAFE_MODE;
7199 MonoDomain *domain = mono_domain_get ();
7205 while (data [len]) len++;
7207 return mono_string_new_utf16_checked (domain, data, len, error);
7211 * mono_string_from_utf32:
7212 * \param data the UTF-32 string (LPWSTR) to convert
7213 * Converts a UTF-32 (UCS-4) string to a \c MonoString.
7214 * \returns a \c MonoString.
7217 mono_string_from_utf32 (mono_unichar4 *data)
7220 MonoString *result = mono_string_from_utf32_checked (data, &error);
7221 mono_error_cleanup (&error);
7226 * mono_string_from_utf32_checked:
7227 * \param data the UTF-32 string (LPWSTR) to convert
7228 * \param error set on error
7229 * Converts a UTF-32 (UCS-4) string to a \c MonoString.
7230 * \returns a \c MonoString. On failure returns NULL and sets \p error.
7233 mono_string_from_utf32_checked (mono_unichar4 *data, MonoError *error)
7235 MONO_REQ_GC_UNSAFE_MODE;
7238 MonoString* result = NULL;
7239 mono_unichar2 *utf16_output = NULL;
7240 GError *gerror = NULL;
7241 glong items_written;
7247 while (data [len]) len++;
7249 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &gerror);
7252 g_error_free (gerror);
7254 result = mono_string_from_utf16_checked (utf16_output, error);
7255 g_free (utf16_output);
7260 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
7262 MONO_REQ_GC_UNSAFE_MODE;
7269 r = mono_string_to_utf8_ignore (s);
7271 r = mono_string_to_utf8_checked (s, error);
7272 if (!mono_error_ok (error))
7279 len = strlen (r) + 1;
7281 mp_s = (char *)mono_mempool_alloc (mp, len);
7283 mp_s = (char *)mono_image_alloc (image, len);
7285 memcpy (mp_s, r, len);
7293 * mono_string_to_utf8_image:
7294 * \param s a \c System.String
7295 * Same as \c mono_string_to_utf8, but allocate the string from the image mempool.
7298 mono_string_to_utf8_image (MonoImage *image, MonoStringHandle s, MonoError *error)
7300 MONO_REQ_GC_UNSAFE_MODE;
7302 return mono_string_to_utf8_internal (NULL, image, MONO_HANDLE_RAW (s), FALSE, error); /* FIXME pin the string */
7306 * mono_string_to_utf8_mp:
7307 * \param s a \c System.String
7308 * Same as \c mono_string_to_utf8, but allocate the string from a mempool.
7311 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
7313 MONO_REQ_GC_UNSAFE_MODE;
7315 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
7319 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
7322 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
7324 eh_callbacks = *cbs;
7327 MonoRuntimeExceptionHandlingCallbacks *
7328 mono_get_eh_callbacks (void)
7330 return &eh_callbacks;
7334 * mono_raise_exception:
7335 * \param ex exception object
7336 * Signal the runtime that the exception \p ex has been raised in unmanaged code.
7339 mono_raise_exception (MonoException *ex)
7341 MONO_REQ_GC_UNSAFE_MODE;
7344 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
7345 * that will cause gcc to omit the function epilog, causing problems when
7346 * the JIT tries to walk the stack, since the return address on the stack
7347 * will point into the next function in the executable, not this one.
7349 eh_callbacks.mono_raise_exception (ex);
7353 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
7355 MONO_REQ_GC_UNSAFE_MODE;
7357 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
7361 * mono_wait_handle_new:
7362 * \param domain Domain where the object will be created
7363 * \param handle Handle for the wait handle
7364 * \param error set on error.
7365 * \returns A new \c MonoWaitHandle created in the given domain for the
7366 * given handle. On failure returns NULL and sets \p error.
7369 mono_wait_handle_new (MonoDomain *domain, HANDLE handle, MonoError *error)
7371 MONO_REQ_GC_UNSAFE_MODE;
7373 MonoWaitHandle *res;
7374 gpointer params [1];
7375 static MonoMethod *handle_set;
7378 res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, error);
7379 return_val_if_nok (error, NULL);
7381 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
7383 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
7385 params [0] = &handle;
7387 mono_runtime_invoke_checked (handle_set, res, params, error);
7392 mono_wait_handle_get_handle (MonoWaitHandle *handle)
7394 MONO_REQ_GC_UNSAFE_MODE;
7396 static MonoClassField *f_safe_handle = NULL;
7399 if (!f_safe_handle) {
7400 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safeWaitHandle");
7401 g_assert (f_safe_handle);
7404 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
7410 mono_runtime_capture_context (MonoDomain *domain, MonoError *error)
7412 MONO_REQ_GC_UNSAFE_MODE;
7414 RuntimeInvokeFunction runtime_invoke;
7418 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
7419 MonoMethod *method = mono_get_context_capture_method ();
7420 MonoMethod *wrapper;
7423 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
7424 domain->capture_context_runtime_invoke = mono_compile_method_checked (wrapper, error);
7425 return_val_if_nok (error, NULL);
7426 domain->capture_context_method = mono_compile_method_checked (method, error);
7427 return_val_if_nok (error, NULL);
7430 runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
7432 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
7435 * mono_async_result_new:
7436 * \param domain domain where the object will be created.
7437 * \param handle wait handle.
7438 * \param state state to pass to AsyncResult
7439 * \param data C closure data.
7440 * \param error set on error.
7441 * Creates a new MonoAsyncResult (\c AsyncResult C# class) in the given domain.
7442 * If the handle is not null, the handle is initialized to a \c MonoWaitHandle.
7443 * On failure returns NULL and sets \p error.
7446 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data, MonoError *error)
7448 MONO_REQ_GC_UNSAFE_MODE;
7451 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, error);
7452 return_val_if_nok (error, NULL);
7453 MonoObject *context = mono_runtime_capture_context (domain, error);
7454 return_val_if_nok (error, NULL);
7455 /* we must capture the execution context from the original thread */
7457 MONO_OBJECT_SETREF (res, execution_context, context);
7458 /* note: result may be null if the flow is suppressed */
7461 res->data = (void **)data;
7462 MONO_OBJECT_SETREF (res, object_data, object_data);
7463 MONO_OBJECT_SETREF (res, async_state, state);
7464 MonoWaitHandle *wait_handle = mono_wait_handle_new (domain, handle, error);
7465 return_val_if_nok (error, NULL);
7467 MONO_OBJECT_SETREF (res, handle, (MonoObject *) wait_handle);
7469 res->sync_completed = FALSE;
7470 res->completed = FALSE;
7476 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
7478 MONO_REQ_GC_UNSAFE_MODE;
7485 g_assert (ares->async_delegate);
7487 ac = (MonoAsyncCall*) ares->object_data;
7489 res = mono_runtime_delegate_invoke_checked (ares->async_delegate, (void**) &ares->async_state, &error);
7490 if (mono_error_set_pending_exception (&error))
7493 gpointer wait_event = NULL;
7495 ac->msg->exc = NULL;
7497 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args, &error);
7499 /* The exit side of the invoke must not be aborted as it would leave the runtime in an undefined state */
7500 mono_threads_begin_abort_protected_block ();
7502 if (!ac->msg->exc) {
7503 MonoException *ex = mono_error_convert_to_exception (&error);
7504 ac->msg->exc = (MonoObject *)ex;
7506 mono_error_cleanup (&error);
7509 MONO_OBJECT_SETREF (ac, res, res);
7511 mono_monitor_enter ((MonoObject*) ares);
7512 ares->completed = 1;
7514 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
7515 mono_monitor_exit ((MonoObject*) ares);
7517 if (wait_event != NULL)
7518 mono_w32event_set (wait_event);
7520 error_init (&error); //the else branch would leave it in an undefined state
7522 mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
7524 mono_threads_end_abort_protected_block ();
7526 if (mono_error_set_pending_exception (&error))
7534 mono_message_init (MonoDomain *domain,
7535 MonoMethodMessage *this_obj,
7536 MonoReflectionMethod *method,
7537 MonoArray *out_args,
7540 MONO_REQ_GC_UNSAFE_MODE;
7542 static MonoMethod *init_message_method = NULL;
7544 if (!init_message_method) {
7545 init_message_method = mono_class_get_method_from_name (mono_defaults.mono_method_message_class, "InitMessage", 2);
7546 g_assert (init_message_method != NULL);
7550 /* FIXME set domain instead? */
7551 g_assert (domain == mono_domain_get ());
7558 mono_runtime_invoke_checked (init_message_method, this_obj, args, error);
7559 return is_ok (error);
7562 #ifndef DISABLE_REMOTING
7564 * mono_remoting_invoke:
7565 * \param real_proxy pointer to a \c RealProxy object
7566 * \param msg The \c MonoMethodMessage to execute
7567 * \param exc used to store exceptions
7568 * \param out_args used to store output arguments
7569 * This is used to call \c RealProxy::Invoke(). \c RealProxy::Invoke() returns an
7570 * \c IMessage interface and it is not trivial to extract results from there. So
7571 * we call an helper method \c PrivateInvoke instead of calling
7572 * \c RealProxy::Invoke() directly.
7573 * \returns the result object.
7576 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, MonoObject **exc, MonoArray **out_args, MonoError *error)
7578 MONO_REQ_GC_UNSAFE_MODE;
7581 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
7588 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
7591 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
7593 mono_error_set_not_supported (error, "Linked away.");
7596 real_proxy->vtable->domain->private_invoke_method = im;
7599 pa [0] = real_proxy;
7604 o = mono_runtime_try_invoke (im, NULL, pa, exc, error);
7605 return_val_if_nok (error, NULL);
7612 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
7613 MonoObject **exc, MonoArray **out_args, MonoError *error)
7615 MONO_REQ_GC_UNSAFE_MODE;
7617 static MonoClass *object_array_klass;
7622 MonoMethodSignature *sig;
7624 int i, j, outarg_count = 0;
7626 #ifndef DISABLE_REMOTING
7627 if (target && mono_object_is_transparent_proxy (target)) {
7628 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
7629 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7630 target = tp->rp->unwrapped_server;
7632 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args, error);
7637 domain = mono_domain_get ();
7638 method = msg->method->method;
7639 sig = mono_method_signature (method);
7641 for (i = 0; i < sig->param_count; i++) {
7642 if (sig->params [i]->byref)
7646 if (!object_array_klass) {
7649 klass = mono_array_class_get (mono_defaults.object_class, 1);
7652 mono_memory_barrier ();
7653 object_array_klass = klass;
7656 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, error);
7657 return_val_if_nok (error, NULL);
7659 mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
7662 MonoObject *ret = mono_runtime_try_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc, error);
7663 return_val_if_nok (error, NULL);
7665 for (i = 0, j = 0; i < sig->param_count; i++) {
7666 if (sig->params [i]->byref) {
7668 arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
7669 mono_array_setref (*out_args, j, arg);
7678 * prepare_to_string_method:
7680 * @target: Set to @obj or unboxed value if a valuetype
7682 * Returns: the ToString override for @obj. If @obj is a valuetype, @target is unboxed otherwise it's @obj.
7685 prepare_to_string_method (MonoObject *obj, void **target)
7687 MONO_REQ_GC_UNSAFE_MODE;
7689 static MonoMethod *to_string = NULL;
7697 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
7699 method = mono_object_get_virtual_method (obj, to_string);
7701 // Unbox value type if needed
7702 if (mono_class_is_valuetype (mono_method_get_class (method))) {
7703 *target = mono_object_unbox (obj);
7709 * mono_object_to_string:
7710 * \param obj The object
7711 * \param exc Any exception thrown by \c ToString. May be NULL.
7712 * \returns the result of calling \c ToString on an object.
7715 mono_object_to_string (MonoObject *obj, MonoObject **exc)
7718 MonoString *s = NULL;
7720 MonoMethod *method = prepare_to_string_method (obj, &target);
7722 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
7723 if (*exc == NULL && !mono_error_ok (&error))
7724 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
7726 mono_error_cleanup (&error);
7728 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
7729 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
7736 * mono_object_to_string_checked:
7737 * \param obj The object
7738 * \param error Set on error.
7739 * \returns the result of calling \c ToString() on an object. If the
7740 * method cannot be invoked or if it raises an exception, sets \p error
7744 mono_object_to_string_checked (MonoObject *obj, MonoError *error)
7748 MonoMethod *method = prepare_to_string_method (obj, &target);
7749 return (MonoString*) mono_runtime_invoke_checked (method, target, NULL, error);
7753 * mono_object_try_to_string:
7754 * \param obj The object
7755 * \param exc Any exception thrown by \c ToString(). Must not be NULL.
7756 * \param error Set if method cannot be invoked.
7757 * \returns the result of calling \c ToString() on an object. If the
7758 * method cannot be invoked sets \p error, if it raises an exception sets \p exc,
7762 mono_object_try_to_string (MonoObject *obj, MonoObject **exc, MonoError *error)
7767 MonoMethod *method = prepare_to_string_method (obj, &target);
7768 return (MonoString*) mono_runtime_try_invoke (method, target, NULL, exc, error);
7774 get_native_backtrace (MonoException *exc_raw)
7776 HANDLE_FUNCTION_ENTER ();
7777 MONO_HANDLE_DCL(MonoException, exc);
7778 char * trace = mono_exception_handle_get_native_backtrace (exc);
7779 HANDLE_FUNCTION_RETURN_VAL (trace);
7783 * mono_print_unhandled_exception:
7784 * \param exc The exception
7785 * Prints the unhandled exception.
7788 mono_print_unhandled_exception (MonoObject *exc)
7790 MONO_REQ_GC_UNSAFE_MODE;
7793 char *message = (char*)"";
7794 gboolean free_message = FALSE;
7797 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
7798 message = g_strdup ("OutOfMemoryException");
7799 free_message = TRUE;
7800 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
7801 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
7802 free_message = TRUE;
7805 if (((MonoException*)exc)->native_trace_ips) {
7806 message = get_native_backtrace ((MonoException*)exc);
7807 free_message = TRUE;
7809 MonoObject *other_exc = NULL;
7810 str = mono_object_try_to_string (exc, &other_exc, &error);
7811 if (other_exc == NULL && !is_ok (&error))
7812 other_exc = (MonoObject*)mono_error_convert_to_exception (&error);
7814 mono_error_cleanup (&error);
7816 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
7817 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
7819 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
7820 original_backtrace, nested_backtrace);
7822 g_free (original_backtrace);
7823 g_free (nested_backtrace);
7824 free_message = TRUE;
7826 message = mono_string_to_utf8_checked (str, &error);
7827 if (!mono_error_ok (&error)) {
7828 mono_error_cleanup (&error);
7829 message = (char *) "";
7831 free_message = TRUE;
7838 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
7839 * exc->vtable->klass->name, message);
7841 g_printerr ("\nUnhandled Exception:\n%s\n", message);
7848 * mono_delegate_ctor_with_method:
7849 * \param this pointer to an uninitialized delegate object
7850 * \param target target object
7851 * \param addr pointer to native code
7852 * \param method method
7853 * \param error set on error.
7854 * Initialize a delegate and sets a specific method, not the one
7855 * associated with \p addr. This is useful when sharing generic code.
7856 * In that case \p addr will most probably not be associated with the
7857 * correct instantiation of the method.
7858 * On failure returns FALSE and sets \p error.
7861 mono_delegate_ctor_with_method (MonoObjectHandle this_obj, MonoObjectHandle target, gpointer addr, MonoMethod *method, MonoError *error)
7863 MONO_REQ_GC_UNSAFE_MODE;
7866 MonoDelegateHandle delegate = MONO_HANDLE_CAST (MonoDelegate, this_obj);
7868 g_assert (!MONO_HANDLE_IS_NULL (this_obj));
7871 MonoClass *klass = mono_handle_class (this_obj);
7872 g_assert (mono_class_has_parent (klass, mono_defaults.multicastdelegate_class));
7875 MONO_HANDLE_SETVAL (delegate, method, MonoMethod*, method);
7877 mono_stats.delegate_creations++;
7879 #ifndef DISABLE_REMOTING
7880 if (!MONO_HANDLE_IS_NULL (target) && mono_class_is_transparent_proxy (mono_handle_class (target))) {
7882 method = mono_marshal_get_remoting_invoke (method);
7883 #ifdef ENABLE_INTERPRETER
7884 //g_error ("need RuntimeMethod in method_ptr when using interpreter");
7886 MONO_HANDLE_SETVAL (delegate, method_ptr, gpointer, mono_compile_method_checked (method, error));
7887 return_val_if_nok (error, FALSE);
7888 MONO_HANDLE_SET (delegate, target, target);
7892 MONO_HANDLE_SETVAL (delegate, method_ptr, gpointer, addr);
7893 MONO_HANDLE_SET (delegate, target, target);
7896 MONO_HANDLE_SETVAL (delegate, invoke_impl, gpointer, callbacks.create_delegate_trampoline (MONO_HANDLE_DOMAIN (delegate), mono_handle_class (delegate)));
7897 if (callbacks.init_delegate)
7898 callbacks.init_delegate (MONO_HANDLE_RAW (delegate)); /* FIXME: update init_delegate callback to take a MonoDelegateHandle */
7903 * mono_delegate_ctor:
7904 * \param this pointer to an uninitialized delegate object
7905 * \param target target object
7906 * \param addr pointer to native code
7907 * \param error set on error.
7908 * This is used to initialize a delegate.
7909 * On failure returns FALSE and sets \p error.
7912 mono_delegate_ctor (MonoObjectHandle this_obj, MonoObjectHandle target, gpointer addr, MonoError *error)
7914 MONO_REQ_GC_UNSAFE_MODE;
7917 MonoDomain *domain = mono_domain_get ();
7919 MonoMethod *method = NULL;
7923 ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
7925 if (!ji && domain != mono_get_root_domain ())
7926 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
7928 method = mono_jit_info_get_method (ji);
7929 g_assert (!mono_class_is_gtd (method->klass));
7932 return mono_delegate_ctor_with_method (this_obj, target, addr, method, error);
7936 * mono_method_call_message_new:
7937 * \param method method to encapsulate
7938 * \param params parameters to the method
7939 * \param invoke optional, delegate invoke.
7940 * \param cb async callback delegate.
7941 * \param state state passed to the async callback.
7942 * \param error set on error.
7943 * Translates arguments pointers into a \c MonoMethodMessage.
7944 * On failure returns NULL and sets \p error.
7947 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
7948 MonoDelegate **cb, MonoObject **state, MonoError *error)
7950 MONO_REQ_GC_UNSAFE_MODE;
7954 MonoDomain *domain = mono_domain_get ();
7955 MonoMethodSignature *sig = mono_method_signature (method);
7956 MonoMethodMessage *msg;
7959 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
7960 return_val_if_nok (error, NULL);
7963 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, error);
7964 return_val_if_nok (error, NULL);
7965 mono_message_init (domain, msg, rm, NULL, error);
7966 return_val_if_nok (error, NULL);
7967 count = sig->param_count - 2;
7969 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
7970 return_val_if_nok (error, NULL);
7971 mono_message_init (domain, msg, rm, NULL, error);
7972 return_val_if_nok (error, NULL);
7973 count = sig->param_count;
7976 for (i = 0; i < count; i++) {
7981 if (sig->params [i]->byref)
7982 vpos = *((gpointer *)params [i]);
7986 klass = mono_class_from_mono_type (sig->params [i]);
7988 if (klass->valuetype) {
7989 arg = mono_value_box_checked (domain, klass, vpos, error);
7990 return_val_if_nok (error, NULL);
7992 arg = *((MonoObject **)vpos);
7994 mono_array_setref (msg->args, i, arg);
7997 if (cb != NULL && state != NULL) {
7998 *cb = *((MonoDelegate **)params [i]);
8000 *state = *((MonoObject **)params [i]);
8007 * mono_method_return_message_restore:
8009 * Restore results from message based processing back to arguments pointers
8012 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args, MonoError *error)
8014 MONO_REQ_GC_UNSAFE_MODE;
8018 MonoMethodSignature *sig = mono_method_signature (method);
8019 int i, j, type, size, out_len;
8021 if (out_args == NULL)
8023 out_len = mono_array_length (out_args);
8027 for (i = 0, j = 0; i < sig->param_count; i++) {
8028 MonoType *pt = sig->params [i];
8033 mono_error_set_execution_engine (error, "The proxy call returned an incorrect number of output arguments");
8037 arg = (char *)mono_array_get (out_args, gpointer, j);
8040 g_assert (type != MONO_TYPE_VOID);
8042 if (MONO_TYPE_IS_REFERENCE (pt)) {
8043 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
8046 MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
8047 size = mono_class_value_size (klass, NULL);
8048 if (klass->has_references)
8049 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
8051 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
8053 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
8054 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
8063 #ifndef DISABLE_REMOTING
8066 * mono_load_remote_field:
8067 * \param this pointer to an object
8068 * \param klass klass of the object containing \p field
8069 * \param field the field to load
8070 * \param res a storage to store the result
8071 * This method is called by the runtime on attempts to load fields of
8072 * transparent proxy objects. \p this points to such TP, \p klass is the class of
8073 * the object containing \p field. \p res is a storage location which can be
8074 * used to store the result.
8075 * \returns an address pointing to the value of field.
8078 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
8081 gpointer result = mono_load_remote_field_checked (this_obj, klass, field, res, &error);
8082 mono_error_cleanup (&error);
8087 * mono_load_remote_field_checked:
8088 * \param this pointer to an object
8089 * \param klass klass of the object containing \p field
8090 * \param field the field to load
8091 * \param res a storage to store the result
8092 * \param error set on error
8093 * This method is called by the runtime on attempts to load fields of
8094 * transparent proxy objects. \p this points to such TP, \p klass is the class of
8095 * the object containing \p field. \p res is a storage location which can be
8096 * used to store the result.
8097 * \returns an address pointing to the value of field. On failure returns NULL and sets \p error.
8100 mono_load_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res, MonoError *error)
8102 MONO_REQ_GC_UNSAFE_MODE;
8104 static MonoMethod *getter = NULL;
8108 MonoDomain *domain = mono_domain_get ();
8109 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8110 MonoClass *field_class;
8111 MonoMethodMessage *msg;
8112 MonoArray *out_args;
8116 g_assert (mono_object_is_transparent_proxy (this_obj));
8117 g_assert (res != NULL);
8119 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8120 mono_field_get_value (tp->rp->unwrapped_server, field, res);
8125 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
8127 mono_error_set_not_supported (error, "Linked away.");
8132 field_class = mono_class_from_mono_type (field->type);
8134 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8135 return_val_if_nok (error, NULL);
8136 out_args = mono_array_new_checked (domain, mono_defaults.object_class, 1, error);
8137 return_val_if_nok (error, NULL);
8138 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, error);
8139 return_val_if_nok (error, NULL);
8140 mono_message_init (domain, msg, rm, out_args, error);
8141 return_val_if_nok (error, NULL);
8143 full_name = mono_type_get_full_name (klass);
8144 MonoString *full_name_str = mono_string_new_checked (domain, full_name, error);
8146 return_val_if_nok (error, NULL);
8147 mono_array_setref (msg->args, 0, full_name_str);
8148 MonoString *field_name = mono_string_new_checked (domain, mono_field_get_name (field), error);
8149 return_val_if_nok (error, NULL);
8150 mono_array_setref (msg->args, 1, field_name);
8152 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8153 return_val_if_nok (error, NULL);
8156 mono_error_set_exception_instance (error, (MonoException *)exc);
8160 if (mono_array_length (out_args) == 0)
8163 mono_gc_wbarrier_generic_store (res, mono_array_get (out_args, MonoObject *, 0));
8165 if (field_class->valuetype) {
8166 return ((char *)*res) + sizeof (MonoObject);
8172 * mono_load_remote_field_new:
8176 * Missing documentation.
8179 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
8183 MonoObject *result = mono_load_remote_field_new_checked (this_obj, klass, field, &error);
8184 mono_error_cleanup (&error);
8189 * mono_load_remote_field_new_checked:
8190 * \param this pointer to an object
8191 * \param klass klass of the object containing \p field
8192 * \param field the field to load
8193 * \param error set on error.
8194 * This method is called by the runtime on attempts to load fields of
8195 * transparent proxy objects. \p this points to such TP, \p klass is the class of
8196 * the object containing \p field.
8197 * \returns a freshly allocated object containing the value of the field. On failure returns NULL and sets \p error.
8200 mono_load_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoError *error)
8202 MONO_REQ_GC_UNSAFE_MODE;
8206 static MonoMethod *tp_load = NULL;
8208 g_assert (mono_object_is_transparent_proxy (this_obj));
8211 tp_load = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "LoadRemoteFieldNew", -1);
8213 mono_error_set_not_supported (error, "Linked away.");
8218 /* MonoType *type = mono_class_get_type (klass); */
8224 return mono_runtime_invoke_checked (tp_load, this_obj, args, error);
8228 * mono_store_remote_field:
8229 * \param this_obj pointer to an object
8230 * \param klass klass of the object containing \p field
8231 * \param field the field to load
8232 * \param val the value/object to store
8233 * This method is called by the runtime on attempts to store fields of
8234 * transparent proxy objects. \p this_obj points to such TP, \p klass is the class of
8235 * the object containing \p field. \p val is the new value to store in \p field.
8238 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
8241 (void) mono_store_remote_field_checked (this_obj, klass, field, val, &error);
8242 mono_error_cleanup (&error);
8246 * mono_store_remote_field_checked:
8247 * \param this_obj pointer to an object
8248 * \param klass klass of the object containing \p field
8249 * \param field the field to load
8250 * \param val the value/object to store
8251 * \param error set on error
8252 * This method is called by the runtime on attempts to store fields of
8253 * transparent proxy objects. \p this_obj points to such TP, \p klass is the class of
8254 * the object containing \p field. \p val is the new value to store in \p field.
8255 * \returns on success returns TRUE, on failure returns FALSE and sets \p error.
8258 mono_store_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val, MonoError *error)
8261 MONO_REQ_GC_UNSAFE_MODE;
8265 MonoDomain *domain = mono_domain_get ();
8266 MonoClass *field_class;
8269 g_assert (mono_object_is_transparent_proxy (this_obj));
8271 field_class = mono_class_from_mono_type (field->type);
8273 if (field_class->valuetype) {
8274 arg = mono_value_box_checked (domain, field_class, val, error);
8275 return_val_if_nok (error, FALSE);
8277 arg = *((MonoObject**)val);
8280 return mono_store_remote_field_new_checked (this_obj, klass, field, arg, error);
8284 * mono_store_remote_field_new:
8289 * Missing documentation
8292 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
8295 (void) mono_store_remote_field_new_checked (this_obj, klass, field, arg, &error);
8296 mono_error_cleanup (&error);
8300 * mono_store_remote_field_new_checked:
8306 * Missing documentation
8309 mono_store_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg, MonoError *error)
8311 MONO_REQ_GC_UNSAFE_MODE;
8313 static MonoMethod *tp_store = NULL;
8317 g_assert (mono_object_is_transparent_proxy (this_obj));
8320 tp_store = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "StoreRemoteField", -1);
8322 mono_error_set_not_supported (error, "Linked away.");
8332 mono_runtime_invoke_checked (tp_store, this_obj, args, error);
8333 return is_ok (error);
8338 * mono_create_ftnptr:
8340 * Given a function address, create a function descriptor for it.
8341 * This is only needed on some platforms.
8344 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
8346 return callbacks.create_ftnptr (domain, addr);
8350 * mono_get_addr_from_ftnptr:
8352 * Given a pointer to a function descriptor, return the function address.
8353 * This is only needed on some platforms.
8356 mono_get_addr_from_ftnptr (gpointer descr)
8358 return callbacks.get_addr_from_ftnptr (descr);
8362 * mono_string_chars:
8363 * \param s a \c MonoString
8364 * \returns a pointer to the UTF-16 characters stored in the \c MonoString
8367 mono_string_chars (MonoString *s)
8369 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
8375 * mono_string_length:
8376 * \param s MonoString
8377 * \returns the length in characters of the string
8380 mono_string_length (MonoString *s)
8382 MONO_REQ_GC_UNSAFE_MODE;
8388 * mono_string_handle_length:
8389 * \param s \c MonoString
8390 * \returns the length in characters of the string
8393 mono_string_handle_length (MonoStringHandle s)
8395 MONO_REQ_GC_UNSAFE_MODE;
8397 return MONO_HANDLE_GETVAL (s, length);
8402 * mono_array_length:
8403 * \param array a \c MonoArray*
8404 * \returns the total number of elements in the array. This works for
8405 * both vectors and multidimensional arrays.
8408 mono_array_length (MonoArray *array)
8410 MONO_REQ_GC_UNSAFE_MODE;
8412 return array->max_length;
8416 * mono_array_addr_with_size:
8417 * \param array a \c MonoArray*
8418 * \param size size of the array elements
8419 * \param idx index into the array
8420 * Use this function to obtain the address for the \p idx item on the
8421 * \p array containing elements of size \p size.
8423 * This method performs no bounds checking or type checking.
8424 * \returns the address of the \p idx element in the array.
8427 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
8429 MONO_REQ_GC_UNSAFE_MODE;
8431 return ((char*)(array)->vector) + size * idx;
8436 mono_glist_to_array (GList *list, MonoClass *eclass, MonoError *error)
8438 MonoDomain *domain = mono_domain_get ();
8446 len = g_list_length (list);
8447 res = mono_array_new_checked (domain, eclass, len, error);
8448 return_val_if_nok (error, NULL);
8450 for (i = 0; list; list = list->next, i++)
8451 mono_array_set (res, gpointer, i, list->data);
8458 * The following section is purely to declare prototypes and
8459 * document the API, as these C files are processed by our
8465 * \param array array to alter
8466 * \param element_type A C type name, this macro will use the sizeof(type) to determine the element size
8467 * \param index index into the array
8468 * \param value value to set
8469 * Value Type version: This sets the \p index's element of the \p array
8470 * with elements of size sizeof(type) to the provided \p value.
8472 * This macro does not attempt to perform type checking or bounds checking.
8474 * Use this to set value types in a \c MonoArray.
8476 void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
8481 * mono_array_setref:
8482 * \param array array to alter
8483 * \param index index into the array
8484 * \param value value to set
8485 * Reference Type version. This sets the \p index's element of the
8486 * \p array with elements of size sizeof(type) to the provided \p value.
8488 * This macro does not attempt to perform type checking or bounds checking.
8490 * Use this to reference types in a \c MonoArray.
8492 void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
8498 * \param array array on which to operate on
8499 * \param element_type C element type (example: \c MonoString*, \c int, \c MonoObject*)
8500 * \param index index into the array
8502 * Use this macro to retrieve the \p index element of an \p array and
8503 * extract the value assuming that the elements of the array match
8504 * the provided type value.
8506 * This method can be used with both arrays holding value types and
8507 * reference types. For reference types, the \p type parameter should
8508 * be a \c MonoObject* or any subclass of it, like \c MonoString*.
8510 * This macro does not attempt to perform type checking or bounds checking.
8512 * \returns The element at the \p index position in the \p array.
8514 Type mono_array_get (MonoArray *array, Type element_type, uintptr_t index)