2 * object.c: Object creation for the Mono runtime
5 * Miguel de Icaza (miguel@ximian.com)
6 * Paolo Molaro (lupus@ximian.com)
8 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
9 * Copyright 2004-2011 Novell, Inc (http://www.novell.com)
10 * Copyright 2001 Xamarin Inc (http://www.xamarin.com)
11 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
20 #include <mono/metadata/mono-endian.h>
21 #include <mono/metadata/tabledefs.h>
22 #include <mono/metadata/tokentype.h>
23 #include <mono/metadata/loader.h>
24 #include <mono/metadata/object.h>
25 #include <mono/metadata/gc-internals.h>
26 #include <mono/metadata/exception.h>
27 #include <mono/metadata/exception-internals.h>
28 #include <mono/metadata/domain-internals.h>
29 #include "mono/metadata/metadata-internals.h"
30 #include "mono/metadata/class-internals.h"
31 #include <mono/metadata/assembly.h>
32 #include <mono/metadata/marshal.h>
33 #include "mono/metadata/debug-helpers.h"
34 #include "mono/metadata/marshal.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/mono-debug-debugger.h"
41 #include <mono/metadata/gc-internals.h>
42 #include <mono/metadata/verify-internals.h>
43 #include <mono/metadata/reflection-internals.h>
44 #include <mono/metadata/w32event.h>
45 #include <mono/utils/strenc.h>
46 #include <mono/utils/mono-counters.h>
47 #include <mono/utils/mono-error-internals.h>
48 #include <mono/utils/mono-memory-model.h>
49 #include <mono/utils/checked-build.h>
50 #include <mono/utils/mono-threads.h>
51 #include <mono/utils/mono-threads-coop.h>
52 #include "cominterop.h"
53 #include <mono/utils/w32api.h>
56 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error);
59 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error);
62 free_main_args (void);
65 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error);
68 class_get_virtual_method (MonoClass *klass, MonoMethod *method, gboolean is_proxy, MonoError *error);
70 /* Class lazy loading functions */
71 static GENERATE_GET_CLASS_WITH_CACHE (pointer, System.Reflection, Pointer)
72 static GENERATE_GET_CLASS_WITH_CACHE (remoting_services, System.Runtime.Remoting, RemotingServices)
73 static GENERATE_GET_CLASS_WITH_CACHE (unhandled_exception_event_args, System, UnhandledExceptionEventArgs)
74 static GENERATE_GET_CLASS_WITH_CACHE (sta_thread_attribute, System, STAThreadAttribute)
75 static GENERATE_GET_CLASS_WITH_CACHE (activation_services, System.Runtime.Remoting.Activation, ActivationServices)
78 #define ldstr_lock() mono_os_mutex_lock (&ldstr_section)
79 #define ldstr_unlock() mono_os_mutex_unlock (&ldstr_section)
80 static mono_mutex_t ldstr_section;
84 * mono_runtime_object_init:
85 * @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 * @this_obj: the object to initialize
101 * @error: set on error.
103 * This function calls the zero-argument constructor (which must
104 * exist) for the given object and returns TRUE on success, or FALSE
105 * on error and sets @error.
108 mono_runtime_object_init_checked (MonoObject *this_obj, MonoError *error)
110 MONO_REQ_GC_UNSAFE_MODE;
112 MonoMethod *method = NULL;
113 MonoClass *klass = this_obj->vtable->klass;
115 mono_error_init (error);
116 method = mono_class_get_method_from_name (klass, ".ctor", 0);
118 g_error ("Could not lookup zero argument constructor for class %s", mono_type_get_full_name (klass));
120 if (method->klass->valuetype)
121 this_obj = (MonoObject *)mono_object_unbox (this_obj);
123 mono_runtime_invoke_checked (method, this_obj, NULL, error);
124 return is_ok (error);
127 /* The pseudo algorithm for type initialization from the spec
128 Note it doesn't say anything about domains - only threads.
130 2. If the type is initialized you are done.
131 2.1. If the type is not yet initialized, try to take an
133 2.2. If successful, record this thread as responsible for
134 initializing the type and proceed to step 2.3.
135 2.2.1. If not, see whether this thread or any thread
136 waiting for this thread to complete already holds the lock.
137 2.2.2. If so, return since blocking would create a deadlock. This thread
138 will now see an incompletely initialized state for the type,
139 but no deadlock will arise.
140 2.2.3 If not, block until the type is initialized then return.
141 2.3 Initialize the parent type and then all interfaces implemented
143 2.4 Execute the type initialization code for this type.
144 2.5 Mark the type as initialized, release the initialization lock,
145 awaken any threads waiting for this type to be initialized,
152 MonoNativeThreadId initializing_tid;
153 guint32 waiting_count;
156 /* condvar used to wait for 'done' becoming TRUE */
158 } TypeInitializationLock;
160 /* for locking access to type_initialization_hash and blocked_thread_hash */
161 static MonoCoopMutex type_initialization_section;
164 mono_type_initialization_lock (void)
166 /* The critical sections protected by this lock in mono_runtime_class_init_full () can block */
167 mono_coop_mutex_lock (&type_initialization_section);
171 mono_type_initialization_unlock (void)
173 mono_coop_mutex_unlock (&type_initialization_section);
177 mono_type_init_lock (TypeInitializationLock *lock)
179 MONO_REQ_GC_NEUTRAL_MODE;
181 mono_coop_mutex_lock (&lock->mutex);
185 mono_type_init_unlock (TypeInitializationLock *lock)
187 mono_coop_mutex_unlock (&lock->mutex);
190 /* from vtable to lock */
191 static GHashTable *type_initialization_hash;
193 /* from thread id to thread id being waited on */
194 static GHashTable *blocked_thread_hash;
197 static MonoThread *main_thread;
199 /* Functions supplied by the runtime */
200 static MonoRuntimeCallbacks callbacks;
203 * mono_thread_set_main:
204 * @thread: thread to set as the main thread
206 * This function can be used to instruct the runtime to treat @thread
207 * as the main thread, ie, the thread that would normally execute the Main()
208 * method. This basically means that at the end of @thread, the runtime will
209 * wait for the existing foreground threads to quit and other such details.
212 mono_thread_set_main (MonoThread *thread)
214 MONO_REQ_GC_UNSAFE_MODE;
216 static gboolean registered = FALSE;
219 MONO_GC_REGISTER_ROOT_SINGLE (main_thread, MONO_ROOT_SOURCE_THREADING, "main thread object");
223 main_thread = thread;
227 mono_thread_get_main (void)
229 MONO_REQ_GC_UNSAFE_MODE;
235 mono_type_initialization_init (void)
237 mono_coop_mutex_init_recursive (&type_initialization_section);
238 type_initialization_hash = g_hash_table_new (NULL, NULL);
239 blocked_thread_hash = g_hash_table_new (NULL, NULL);
240 mono_os_mutex_init_recursive (&ldstr_section);
244 mono_type_initialization_cleanup (void)
247 /* This is causing race conditions with
248 * mono_release_type_locks
250 mono_coop_mutex_destroy (&type_initialization_section);
251 g_hash_table_destroy (type_initialization_hash);
252 type_initialization_hash = NULL;
254 mono_os_mutex_destroy (&ldstr_section);
255 g_hash_table_destroy (blocked_thread_hash);
256 blocked_thread_hash = NULL;
262 * get_type_init_exception_for_vtable:
264 * Return the stored type initialization exception for VTABLE.
266 static MonoException*
267 get_type_init_exception_for_vtable (MonoVTable *vtable)
269 MONO_REQ_GC_UNSAFE_MODE;
272 MonoDomain *domain = vtable->domain;
273 MonoClass *klass = vtable->klass;
277 if (!vtable->init_failed)
278 g_error ("Trying to get the init exception for a non-failed vtable of class %s", mono_type_get_full_name (klass));
281 * If the initializing thread was rudely aborted, the exception is not stored
285 mono_domain_lock (domain);
286 if (domain->type_init_exception_hash)
287 ex = (MonoException *)mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
288 mono_domain_unlock (domain);
291 if (klass->name_space && *klass->name_space)
292 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
294 full_name = g_strdup (klass->name);
295 ex = mono_get_exception_type_initialization_checked (full_name, NULL, &error);
297 return_val_if_nok (&error, NULL);
304 * mono_runtime_class_init:
305 * @vtable: vtable that needs to be initialized
307 * This routine calls the class constructor for @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 * @vtable that neeeds to be initialized
340 * @error set on error
342 * returns TRUE if class constructor .cctor has been initialized successfully, or FALSE otherwise and sets @error.
346 mono_runtime_class_init_full (MonoVTable *vtable, MonoError *error)
348 MONO_REQ_GC_UNSAFE_MODE;
350 MonoMethod *method = NULL;
353 MonoDomain *domain = vtable->domain;
354 TypeInitializationLock *lock;
355 MonoNativeThreadId tid;
356 int do_initialization = 0;
357 MonoDomain *last_domain = NULL;
358 MonoException * pending_tae = NULL;
360 mono_error_init (error);
362 if (vtable->initialized)
365 klass = vtable->klass;
367 if (!klass->image->checked_module_cctor) {
368 mono_image_check_for_module_cctor (klass->image);
369 if (klass->image->has_module_cctor) {
370 MonoClass *module_klass;
371 MonoVTable *module_vtable;
373 module_klass = mono_class_get_checked (klass->image, MONO_TOKEN_TYPE_DEF | 1, error);
378 module_vtable = mono_class_vtable_full (vtable->domain, module_klass, error);
381 if (!mono_runtime_class_init_full (module_vtable, error))
385 method = mono_class_get_cctor (klass);
387 vtable->initialized = 1;
391 tid = mono_native_thread_id_get ();
394 * Due some preprocessing inside a global lock. If we are the first thread
395 * trying to initialize this class, create a separate lock+cond var, and
396 * acquire it before leaving the global lock. The other threads will wait
400 mono_type_initialization_lock ();
401 /* double check... */
402 if (vtable->initialized) {
403 mono_type_initialization_unlock ();
406 if (vtable->init_failed) {
407 mono_type_initialization_unlock ();
409 /* The type initialization already failed once, rethrow the same exception */
410 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
413 lock = (TypeInitializationLock *)g_hash_table_lookup (type_initialization_hash, vtable);
415 /* This thread will get to do the initialization */
416 if (mono_domain_get () != domain) {
417 /* Transfer into the target domain */
418 last_domain = mono_domain_get ();
419 if (!mono_domain_set (domain, FALSE)) {
420 vtable->initialized = 1;
421 mono_type_initialization_unlock ();
422 mono_error_set_exception_instance (error, mono_get_exception_appdomain_unloaded ());
426 lock = (TypeInitializationLock *)g_malloc0 (sizeof (TypeInitializationLock));
427 mono_coop_mutex_init_recursive (&lock->mutex);
428 mono_coop_cond_init (&lock->cond);
429 lock->initializing_tid = tid;
430 lock->waiting_count = 1;
432 /* grab the vtable lock while this thread still owns type_initialization_section */
433 /* This is why type_initialization_lock needs to enter blocking mode */
434 mono_type_init_lock (lock);
435 g_hash_table_insert (type_initialization_hash, vtable, lock);
436 do_initialization = 1;
439 TypeInitializationLock *pending_lock;
441 if (mono_native_thread_id_equals (lock->initializing_tid, tid)) {
442 mono_type_initialization_unlock ();
445 /* see if the thread doing the initialization is already blocked on this thread */
446 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (lock->initializing_tid));
447 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
448 if (mono_native_thread_id_equals (pending_lock->initializing_tid, tid)) {
449 if (!pending_lock->done) {
450 mono_type_initialization_unlock ();
453 /* the thread doing the initialization is blocked on this thread,
454 but on a lock that has already been freed. It just hasn't got
459 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (pending_lock->initializing_tid));
461 ++lock->waiting_count;
462 /* record the fact that we are waiting on the initializing thread */
463 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
465 mono_type_initialization_unlock ();
467 if (do_initialization) {
468 MonoException *exc = NULL;
470 /* We are holding the per-vtable lock, do the actual initialization */
472 mono_threads_begin_abort_protected_block ();
473 mono_runtime_try_invoke (method, NULL, NULL, (MonoObject**) &exc, error);
474 gboolean got_pending_interrupt = mono_threads_end_abort_protected_block ();
476 //exception extracted, error will be set to the right value later
477 if (exc == NULL && !mono_error_ok (error))//invoking failed but exc was not set
478 exc = mono_error_convert_to_exception (error);
480 mono_error_cleanup (error);
482 mono_error_init (error);
484 /* If the initialization failed, mark the class as unusable. */
485 /* Avoid infinite loops */
487 (klass->image == mono_defaults.corlib &&
488 !strcmp (klass->name_space, "System") &&
489 !strcmp (klass->name, "TypeInitializationException")))) {
490 vtable->init_failed = 1;
492 if (klass->name_space && *klass->name_space)
493 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
495 full_name = g_strdup (klass->name);
497 MonoException *exc_to_throw = mono_get_exception_type_initialization_checked (full_name, exc, error);
500 mono_error_assert_ok (error); //We can't recover from this, no way to fail a type we can't alloc a failure.
503 * Store the exception object so it could be thrown on subsequent
506 mono_domain_lock (domain);
507 if (!domain->type_init_exception_hash)
508 domain->type_init_exception_hash = mono_g_hash_table_new_type (mono_aligned_addr_hash, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_DOMAIN, "type initialization exceptions table");
509 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
510 mono_domain_unlock (domain);
514 mono_domain_set (last_domain, TRUE);
515 /* Signal to the other threads that we are done */
517 mono_coop_cond_broadcast (&lock->cond);
519 mono_type_init_unlock (lock);
521 //This can happen if the cctor self-aborts
522 if (exc && mono_object_class (exc) == mono_defaults.threadabortexception_class)
525 //TAEs are blocked around .cctors, they must escape as soon as no cctor is left to run.
526 if (!pending_tae && got_pending_interrupt)
527 pending_tae = mono_thread_try_resume_interruption ();
529 /* this just blocks until the initializing thread is done */
530 mono_type_init_lock (lock);
532 mono_coop_cond_wait (&lock->cond, &lock->mutex);
533 mono_type_init_unlock (lock);
536 /* Do cleanup and setting vtable->initialized inside the global lock again */
537 mono_type_initialization_lock ();
538 if (!do_initialization)
539 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
540 gboolean deleted = unref_type_lock (lock);
542 g_hash_table_remove (type_initialization_hash, vtable);
543 /* Have to set this here since we check it inside the global lock */
544 if (do_initialization && !vtable->init_failed)
545 vtable->initialized = 1;
546 mono_type_initialization_unlock ();
550 mono_error_set_exception_instance (error, pending_tae);
551 else if (vtable->init_failed) {
552 /* Either we were the initializing thread or we waited for the initialization */
553 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
560 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
562 MONO_REQ_GC_NEUTRAL_MODE;
564 MonoVTable *vtable = (MonoVTable*)key;
566 TypeInitializationLock *lock = (TypeInitializationLock*) value;
567 if (mono_native_thread_id_equals (lock->initializing_tid, MONO_UINT_TO_NATIVE_THREAD_ID (GPOINTER_TO_UINT (user))) && !lock->done) {
570 * Have to set this since it cannot be set by the normal code in
571 * mono_runtime_class_init (). In this case, the exception object is not stored,
572 * and get_type_init_exception_for_class () needs to be aware of this.
574 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 * @method: The method to compile.
641 * This JIT-compiles the method, and returns the pointer to the native code
645 mono_compile_method (MonoMethod *method)
648 gpointer result = mono_compile_method_checked (method, &error);
649 mono_error_cleanup (&error);
654 * mono_compile_method:
655 * @method: The method to compile.
656 * @error: set on error.
658 * This JIT-compiles the method, and returns the pointer to the native code
659 * produced. On failure returns NULL and sets @error.
662 mono_compile_method_checked (MonoMethod *method, MonoError *error)
666 MONO_REQ_GC_NEUTRAL_MODE
668 mono_error_init (error);
670 g_assert (callbacks.compile_method);
671 res = callbacks.compile_method (method, error);
676 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper, MonoError *error)
680 MONO_REQ_GC_NEUTRAL_MODE;
682 mono_error_init (error);
683 res = callbacks.create_jump_trampoline (domain, method, add_sync_wrapper, error);
688 mono_runtime_create_delegate_trampoline (MonoClass *klass)
690 MONO_REQ_GC_NEUTRAL_MODE
692 g_assert (callbacks.create_delegate_trampoline);
693 return callbacks.create_delegate_trampoline (mono_domain_get (), klass);
697 * mono_runtime_free_method:
698 * @domain; domain where the method is hosted
699 * @method: method to release
701 * This routine is invoked to free the resources associated with
702 * a method that has been JIT compiled. This is used to discard
703 * methods that were used only temporarily (for example, used in marshalling)
707 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
709 MONO_REQ_GC_NEUTRAL_MODE
711 if (callbacks.free_method)
712 callbacks.free_method (domain, method);
714 mono_method_clear_object (domain, method);
716 mono_free_method (method);
720 * The vtables in the root appdomain are assumed to be reachable by other
721 * roots, and we don't use typed allocation in the other domains.
724 /* The sync block is no longer a GC pointer */
725 #define GC_HEADER_BITMAP (0)
727 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
730 compute_class_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
732 MONO_REQ_GC_NEUTRAL_MODE;
734 MonoClassField *field;
740 max_size = mono_class_data_size (klass) / sizeof (gpointer);
742 max_size = klass->instance_size / sizeof (gpointer);
743 if (max_size > size) {
744 g_assert (offset <= 0);
745 bitmap = (gsize *)g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
750 /*An Ephemeron cannot be marked by sgen*/
751 if (!static_fields && klass->image == mono_defaults.corlib && !strcmp ("Ephemeron", klass->name)) {
753 memset (bitmap, 0, size / 8);
758 for (p = klass; p != NULL; p = p->parent) {
759 gpointer iter = NULL;
760 while ((field = mono_class_get_fields (p, &iter))) {
764 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
766 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
769 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
772 /* FIXME: should not happen, flag as type load error */
773 if (field->type->byref)
776 if (static_fields && field->offset == -1)
780 pos = field->offset / sizeof (gpointer);
783 type = mono_type_get_underlying_type (field->type);
784 switch (type->type) {
787 case MONO_TYPE_FNPTR:
789 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
794 if (klass->image != mono_defaults.corlib)
797 case MONO_TYPE_STRING:
798 case MONO_TYPE_SZARRAY:
799 case MONO_TYPE_CLASS:
800 case MONO_TYPE_OBJECT:
801 case MONO_TYPE_ARRAY:
802 g_assert ((field->offset % sizeof(gpointer)) == 0);
804 g_assert (pos < size || pos <= max_size);
805 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
806 *max_set = MAX (*max_set, pos);
808 case MONO_TYPE_GENERICINST:
809 if (!mono_type_generic_inst_is_valuetype (type)) {
810 g_assert ((field->offset % sizeof(gpointer)) == 0);
812 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
813 *max_set = MAX (*max_set, pos);
818 case MONO_TYPE_VALUETYPE: {
819 MonoClass *fclass = mono_class_from_mono_type (field->type);
820 if (fclass->has_references) {
821 /* remove the object header */
822 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
836 case MONO_TYPE_BOOLEAN:
840 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
851 * mono_class_compute_bitmap:
853 * Mono internal function to compute a bitmap of reference fields in a class.
856 mono_class_compute_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
858 MONO_REQ_GC_NEUTRAL_MODE;
860 return compute_class_bitmap (klass, bitmap, size, offset, max_set, static_fields);
865 * similar to the above, but sets the bits in the bitmap for any non-ref field
866 * and ignores static fields
869 compute_class_non_ref_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset)
871 MonoClassField *field;
876 max_size = class->instance_size / sizeof (gpointer);
877 if (max_size >= size) {
878 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
881 for (p = class; p != NULL; p = p->parent) {
882 gpointer iter = NULL;
883 while ((field = mono_class_get_fields (p, &iter))) {
886 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
888 /* FIXME: should not happen, flag as type load error */
889 if (field->type->byref)
892 pos = field->offset / sizeof (gpointer);
895 type = mono_type_get_underlying_type (field->type);
896 switch (type->type) {
897 #if SIZEOF_VOID_P == 8
901 case MONO_TYPE_FNPTR:
906 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
907 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
908 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
911 #if SIZEOF_VOID_P == 4
915 case MONO_TYPE_FNPTR:
920 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
921 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
922 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
928 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
929 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
930 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
933 case MONO_TYPE_BOOLEAN:
936 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
938 case MONO_TYPE_STRING:
939 case MONO_TYPE_SZARRAY:
940 case MONO_TYPE_CLASS:
941 case MONO_TYPE_OBJECT:
942 case MONO_TYPE_ARRAY:
944 case MONO_TYPE_GENERICINST:
945 if (!mono_type_generic_inst_is_valuetype (type)) {
950 case MONO_TYPE_VALUETYPE: {
951 MonoClass *fclass = mono_class_from_mono_type (field->type);
952 /* remove the object header */
953 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
957 g_assert_not_reached ();
966 * mono_class_insecure_overlapping:
967 * check if a class with explicit layout has references and non-references
968 * fields overlapping.
970 * Returns: TRUE if it is insecure to load the type.
973 mono_class_insecure_overlapping (MonoClass *klass)
977 gsize default_bitmap [4] = {0};
979 gsize default_nrbitmap [4] = {0};
980 int i, insecure = FALSE;
983 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
984 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
986 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
987 int idx = i % (sizeof (bitmap [0]) * 8);
988 if (bitmap [idx] & nrbitmap [idx]) {
993 if (bitmap != default_bitmap)
995 if (nrbitmap != default_nrbitmap)
998 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
1006 ves_icall_string_alloc (int length)
1009 MonoString *str = mono_string_new_size_checked (mono_domain_get (), length, &error);
1010 mono_error_set_pending_exception (&error);
1015 /* LOCKING: Acquires the loader lock */
1017 mono_class_compute_gc_descriptor (MonoClass *klass)
1019 MONO_REQ_GC_NEUTRAL_MODE;
1023 gsize default_bitmap [4] = {0};
1024 static gboolean gcj_inited = FALSE;
1025 MonoGCDescriptor gc_descr;
1028 mono_loader_lock ();
1030 mono_register_jit_icall (ves_icall_object_new_fast, "ves_icall_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
1031 mono_register_jit_icall (ves_icall_string_alloc, "ves_icall_string_alloc", mono_create_icall_signature ("object int"), FALSE);
1034 mono_loader_unlock ();
1038 mono_class_init (klass);
1040 if (klass->gc_descr_inited)
1043 bitmap = default_bitmap;
1044 if (klass == mono_defaults.string_class) {
1045 gc_descr = mono_gc_make_descr_for_string (bitmap, 2);
1046 } else if (klass->rank) {
1047 mono_class_compute_gc_descriptor (klass->element_class);
1048 if (MONO_TYPE_IS_REFERENCE (&klass->element_class->byval_arg)) {
1050 gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
1051 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1052 class->name_space, class->name);*/
1054 /* remove the object header */
1055 bitmap = compute_class_bitmap (klass->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
1056 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));
1057 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1058 class->name_space, class->name);*/
1059 if (bitmap != default_bitmap)
1063 /*static int count = 0;
1066 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1067 gc_descr = mono_gc_make_descr_for_object (bitmap, max_set + 1, klass->instance_size);
1069 if (class->gc_descr == MONO_GC_DESCRIPTOR_NULL)
1070 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
1072 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
1073 if (bitmap != default_bitmap)
1077 /* Publish the data */
1078 mono_loader_lock ();
1079 klass->gc_descr = gc_descr;
1080 mono_memory_barrier ();
1081 klass->gc_descr_inited = TRUE;
1082 mono_loader_unlock ();
1086 * field_is_special_static:
1087 * @fklass: The MonoClass to look up.
1088 * @field: The MonoClassField describing the field.
1090 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1091 * SPECIAL_STATIC_NONE otherwise.
1094 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1096 MONO_REQ_GC_NEUTRAL_MODE;
1099 MonoCustomAttrInfo *ainfo;
1101 ainfo = mono_custom_attrs_from_field_checked (fklass, field, &error);
1102 mono_error_cleanup (&error); /* FIXME don't swallow the error? */
1105 for (i = 0; i < ainfo->num_attrs; ++i) {
1106 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1107 if (klass->image == mono_defaults.corlib) {
1108 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1109 mono_custom_attrs_free (ainfo);
1110 return SPECIAL_STATIC_THREAD;
1112 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1113 mono_custom_attrs_free (ainfo);
1114 return SPECIAL_STATIC_CONTEXT;
1118 mono_custom_attrs_free (ainfo);
1119 return SPECIAL_STATIC_NONE;
1122 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1123 #define mix(a,b,c) { \
1124 a -= c; a ^= rot(c, 4); c += b; \
1125 b -= a; b ^= rot(a, 6); a += c; \
1126 c -= b; c ^= rot(b, 8); b += a; \
1127 a -= c; a ^= rot(c,16); c += b; \
1128 b -= a; b ^= rot(a,19); a += c; \
1129 c -= b; c ^= rot(b, 4); b += a; \
1131 #define final(a,b,c) { \
1132 c ^= b; c -= rot(b,14); \
1133 a ^= c; a -= rot(c,11); \
1134 b ^= a; b -= rot(a,25); \
1135 c ^= b; c -= rot(b,16); \
1136 a ^= c; a -= rot(c,4); \
1137 b ^= a; b -= rot(a,14); \
1138 c ^= b; c -= rot(b,24); \
1142 * mono_method_get_imt_slot:
1144 * The IMT slot is embedded into AOTed code, so this must return the same value
1145 * for the same method across all executions. This means:
1146 * - pointers shouldn't be used as hash values.
1147 * - mono_metadata_str_hash () should be used for hashing strings.
1150 mono_method_get_imt_slot (MonoMethod *method)
1152 MONO_REQ_GC_NEUTRAL_MODE;
1154 MonoMethodSignature *sig;
1156 guint32 *hashes_start, *hashes;
1160 /* This can be used to stress tests the collision code */
1164 * We do this to simplify generic sharing. It will hurt
1165 * performance in cases where a class implements two different
1166 * instantiations of the same generic interface.
1167 * The code in build_imt_slots () depends on this.
1169 if (method->is_inflated)
1170 method = ((MonoMethodInflated*)method)->declaring;
1172 sig = mono_method_signature (method);
1173 hashes_count = sig->param_count + 4;
1174 hashes_start = (guint32 *)malloc (hashes_count * sizeof (guint32));
1175 hashes = hashes_start;
1177 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1178 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1179 method->klass->name_space, method->klass->name, method->name);
1182 /* Initialize hashes */
1183 hashes [0] = mono_metadata_str_hash (method->klass->name);
1184 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1185 hashes [2] = mono_metadata_str_hash (method->name);
1186 hashes [3] = mono_metadata_type_hash (sig->ret);
1187 for (i = 0; i < sig->param_count; i++) {
1188 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1191 /* Setup internal state */
1192 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1194 /* Handle most of the hashes */
1195 while (hashes_count > 3) {
1204 /* Handle the last 3 hashes (all the case statements fall through) */
1205 switch (hashes_count) {
1206 case 3 : c += hashes [2];
1207 case 2 : b += hashes [1];
1208 case 1 : a += hashes [0];
1210 case 0: /* nothing left to add */
1214 g_free (hashes_start);
1215 /* Report the result */
1216 return c % MONO_IMT_SIZE;
1225 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1226 MONO_REQ_GC_NEUTRAL_MODE;
1228 guint32 imt_slot = mono_method_get_imt_slot (method);
1229 MonoImtBuilderEntry *entry;
1231 if (slot_num >= 0 && imt_slot != slot_num) {
1232 /* we build just a single imt slot and this is not it */
1236 entry = (MonoImtBuilderEntry *)g_malloc0 (sizeof (MonoImtBuilderEntry));
1237 entry->key = method;
1238 entry->value.vtable_slot = vtable_slot;
1239 entry->next = imt_builder [imt_slot];
1240 if (imt_builder [imt_slot] != NULL) {
1241 entry->children = imt_builder [imt_slot]->children + 1;
1242 if (entry->children == 1) {
1243 mono_stats.imt_slots_with_collisions++;
1244 *imt_collisions_bitmap |= (1 << imt_slot);
1247 entry->children = 0;
1248 mono_stats.imt_used_slots++;
1250 imt_builder [imt_slot] = entry;
1253 char *method_name = mono_method_full_name (method, TRUE);
1254 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1255 method, method_name, imt_slot, vtable_slot, entry->children);
1256 g_free (method_name);
1263 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1265 MonoMethod *method = e->key;
1266 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1270 method->klass->name_space,
1271 method->klass->name,
1274 printf (" * %s: NULL\n", message);
1280 compare_imt_builder_entries (const void *p1, const void *p2) {
1281 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1282 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1284 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1288 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1290 MONO_REQ_GC_NEUTRAL_MODE;
1292 int count = end - start;
1293 int chunk_start = out_array->len;
1296 for (i = start; i < end; ++i) {
1297 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1298 item->key = sorted_array [i]->key;
1299 item->value = sorted_array [i]->value;
1300 item->has_target_code = sorted_array [i]->has_target_code;
1301 item->is_equals = TRUE;
1303 item->check_target_idx = out_array->len + 1;
1305 item->check_target_idx = 0;
1306 g_ptr_array_add (out_array, item);
1309 int middle = start + count / 2;
1310 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1312 item->key = sorted_array [middle]->key;
1313 item->is_equals = FALSE;
1314 g_ptr_array_add (out_array, item);
1315 imt_emit_ir (sorted_array, start, middle, out_array);
1316 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1322 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1323 MONO_REQ_GC_NEUTRAL_MODE;
1325 int number_of_entries = entries->children + 1;
1326 MonoImtBuilderEntry **sorted_array = (MonoImtBuilderEntry **)malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1327 GPtrArray *result = g_ptr_array_new ();
1328 MonoImtBuilderEntry *current_entry;
1331 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1332 sorted_array [i] = current_entry;
1334 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1336 /*for (i = 0; i < number_of_entries; i++) {
1337 print_imt_entry (" sorted array:", sorted_array [i], i);
1340 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1342 g_free (sorted_array);
1347 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1349 MONO_REQ_GC_NEUTRAL_MODE;
1351 if (imt_builder_entry != NULL) {
1352 if (imt_builder_entry->children == 0 && !fail_tramp && !always_build_imt_trampolines) {
1353 /* No collision, return the vtable slot contents */
1354 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1356 /* Collision, build the trampoline */
1357 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1360 result = imt_trampoline_builder (vtable, domain,
1361 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1362 for (i = 0; i < imt_ir->len; ++i)
1363 g_free (g_ptr_array_index (imt_ir, i));
1364 g_ptr_array_free (imt_ir, TRUE);
1376 static MonoImtBuilderEntry*
1377 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1380 * LOCKING: requires the loader and domain locks.
1384 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1386 MONO_REQ_GC_NEUTRAL_MODE;
1390 guint32 imt_collisions_bitmap = 0;
1391 MonoImtBuilderEntry **imt_builder = (MonoImtBuilderEntry **)calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1392 int method_count = 0;
1393 gboolean record_method_count_for_max_collisions = FALSE;
1394 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1397 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1399 for (i = 0; i < klass->interface_offsets_count; ++i) {
1400 MonoClass *iface = klass->interfaces_packed [i];
1401 int interface_offset = klass->interface_offsets_packed [i];
1402 int method_slot_in_interface, vt_slot;
1404 if (mono_class_has_variant_generic_params (iface))
1405 has_variant_iface = TRUE;
1407 mono_class_setup_methods (iface);
1408 vt_slot = interface_offset;
1409 int mcount = mono_class_get_method_count (iface);
1410 for (method_slot_in_interface = 0; method_slot_in_interface < mcount; method_slot_in_interface++) {
1413 if (slot_num >= 0 && mono_class_is_ginst (iface)) {
1415 * The imt slot of the method is the same as for its declaring method,
1416 * see the comment in mono_method_get_imt_slot (), so we can
1417 * avoid inflating methods which will be discarded by
1418 * add_imt_builder_entry anyway.
1420 method = mono_class_get_method_by_index (mono_class_get_generic_class (iface)->container_class, method_slot_in_interface);
1421 if (mono_method_get_imt_slot (method) != slot_num) {
1426 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1427 if (method->is_generic) {
1428 has_generic_virtual = TRUE;
1433 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1434 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1439 if (extra_interfaces) {
1440 int interface_offset = klass->vtable_size;
1442 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1443 MonoClass* iface = (MonoClass *)list_item->data;
1444 int method_slot_in_interface;
1445 int mcount = mono_class_get_method_count (iface);
1446 for (method_slot_in_interface = 0; method_slot_in_interface < mcount; method_slot_in_interface++) {
1447 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1449 if (method->is_generic)
1450 has_generic_virtual = TRUE;
1451 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1453 interface_offset += mcount;
1456 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1457 /* overwrite the imt slot only if we're building all the entries or if
1458 * we're building this specific one
1460 if (slot_num < 0 || i == slot_num) {
1461 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1464 if (imt_builder [i]) {
1465 MonoImtBuilderEntry *entry;
1467 /* Link entries with imt_builder [i] */
1468 for (entry = entries; entry->next; entry = entry->next) {
1470 MonoMethod *method = (MonoMethod*)entry->key;
1471 char *method_name = mono_method_full_name (method, TRUE);
1472 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1473 g_free (method_name);
1476 entry->next = imt_builder [i];
1477 entries->children += imt_builder [i]->children + 1;
1479 imt_builder [i] = entries;
1482 if (has_generic_virtual || has_variant_iface) {
1484 * There might be collisions later when the the trampoline is expanded.
1486 imt_collisions_bitmap |= (1 << i);
1489 * The IMT trampoline might be called with an instance of one of the
1490 * generic virtual methods, so has to fallback to the IMT trampoline.
1492 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline (vt, i));
1494 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1497 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1501 if (imt_builder [i] != NULL) {
1502 int methods_in_slot = imt_builder [i]->children + 1;
1503 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1504 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1505 record_method_count_for_max_collisions = TRUE;
1507 method_count += methods_in_slot;
1511 mono_stats.imt_number_of_methods += method_count;
1512 if (record_method_count_for_max_collisions) {
1513 mono_stats.imt_method_count_when_max_collisions = method_count;
1516 for (i = 0; i < MONO_IMT_SIZE; i++) {
1517 MonoImtBuilderEntry* entry = imt_builder [i];
1518 while (entry != NULL) {
1519 MonoImtBuilderEntry* next = entry->next;
1524 g_free (imt_builder);
1525 /* we OR the bitmap since we may build just a single imt slot at a time */
1526 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1530 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1531 MONO_REQ_GC_NEUTRAL_MODE;
1533 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1537 * mono_vtable_build_imt_slot:
1538 * @vtable: virtual object table struct
1539 * @imt_slot: slot in the IMT table
1541 * Fill the given @imt_slot in the IMT table of @vtable with
1542 * a trampoline or a trampoline for the case of collisions.
1543 * This is part of the internal mono API.
1545 * LOCKING: Take the domain lock.
1548 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1550 MONO_REQ_GC_NEUTRAL_MODE;
1552 gpointer *imt = (gpointer*)vtable;
1553 imt -= MONO_IMT_SIZE;
1554 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1556 /* no support for extra interfaces: the proxy objects will need
1557 * to build the complete IMT
1558 * Update and heck needs to ahppen inside the proper domain lock, as all
1559 * the changes made to a MonoVTable.
1561 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1562 mono_domain_lock (vtable->domain);
1563 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1564 if (!callbacks.imt_entry_inited (vtable, imt_slot))
1565 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1566 mono_domain_unlock (vtable->domain);
1567 mono_loader_unlock ();
1570 #define THUNK_THRESHOLD 10
1573 * mono_method_alloc_generic_virtual_trampoline:
1575 * @size: size in bytes
1577 * Allocs size bytes to be used for the code of a generic virtual
1578 * trampoline. It's either allocated from the domain's code manager or
1579 * reused from a previously invalidated piece.
1581 * LOCKING: The domain lock must be held.
1584 mono_method_alloc_generic_virtual_trampoline (MonoDomain *domain, int size)
1586 MONO_REQ_GC_NEUTRAL_MODE;
1588 static gboolean inited = FALSE;
1589 static int generic_virtual_trampolines_size = 0;
1592 mono_counters_register ("Generic virtual trampoline bytes",
1593 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_trampolines_size);
1596 generic_virtual_trampolines_size += size;
1598 return mono_domain_code_reserve (domain, size);
1601 typedef struct _GenericVirtualCase {
1605 struct _GenericVirtualCase *next;
1606 } GenericVirtualCase;
1609 * get_generic_virtual_entries:
1611 * Return IMT entries for the generic virtual method instances and
1612 * variant interface methods for vtable slot
1615 static MonoImtBuilderEntry*
1616 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1618 MONO_REQ_GC_NEUTRAL_MODE;
1620 GenericVirtualCase *list;
1621 MonoImtBuilderEntry *entries;
1623 mono_domain_lock (domain);
1624 if (!domain->generic_virtual_cases)
1625 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1627 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1630 for (; list; list = list->next) {
1631 MonoImtBuilderEntry *entry;
1633 if (list->count < THUNK_THRESHOLD)
1636 entry = g_new0 (MonoImtBuilderEntry, 1);
1637 entry->key = list->method;
1638 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1639 entry->has_target_code = 1;
1641 entry->children = entries->children + 1;
1642 entry->next = entries;
1646 mono_domain_unlock (domain);
1648 /* FIXME: Leaking memory ? */
1653 * mono_method_add_generic_virtual_invocation:
1655 * @vtable_slot: pointer to the vtable slot
1656 * @method: the inflated generic virtual method
1657 * @code: the method's code
1659 * Registers a call via unmanaged code to a generic virtual method
1660 * instantiation or variant interface method. If the number of calls reaches a threshold
1661 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1662 * virtual method trampoline.
1665 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1666 gpointer *vtable_slot,
1667 MonoMethod *method, gpointer code)
1669 MONO_REQ_GC_NEUTRAL_MODE;
1671 static gboolean inited = FALSE;
1672 static int num_added = 0;
1673 static int num_freed = 0;
1675 GenericVirtualCase *gvc, *list;
1676 MonoImtBuilderEntry *entries;
1680 mono_domain_lock (domain);
1681 if (!domain->generic_virtual_cases)
1682 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1685 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1686 mono_counters_register ("Freed IMT trampolines", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_freed);
1690 /* Check whether the case was already added */
1691 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1694 if (gvc->method == method)
1699 /* If not found, make a new one */
1701 gvc = (GenericVirtualCase *)mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1702 gvc->method = method;
1705 gvc->next = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1707 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1712 if (++gvc->count == THUNK_THRESHOLD) {
1713 gpointer *old_thunk = (void **)*vtable_slot;
1714 gpointer vtable_trampoline = NULL;
1715 gpointer imt_trampoline = NULL;
1717 if ((gpointer)vtable_slot < (gpointer)vtable) {
1718 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1719 int imt_slot = MONO_IMT_SIZE + displacement;
1721 /* Force the rebuild of the trampoline at the next call */
1722 imt_trampoline = callbacks.get_imt_trampoline (vtable, imt_slot);
1723 *vtable_slot = imt_trampoline;
1725 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline (vtable, (gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1727 entries = get_generic_virtual_entries (domain, vtable_slot);
1729 sorted = imt_sort_slot_entries (entries);
1731 *vtable_slot = imt_trampoline_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1735 MonoImtBuilderEntry *next = entries->next;
1740 for (i = 0; i < sorted->len; ++i)
1741 g_free (g_ptr_array_index (sorted, i));
1742 g_ptr_array_free (sorted, TRUE);
1744 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1749 mono_domain_unlock (domain);
1752 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error);
1755 * mono_class_vtable:
1756 * @domain: the application domain
1757 * @class: the class to initialize
1759 * VTables are domain specific because we create domain specific code, and
1760 * they contain the domain specific static class data.
1761 * On failure, NULL is returned, and class->exception_type is set.
1764 mono_class_vtable (MonoDomain *domain, MonoClass *klass)
1767 MonoVTable* vtable = mono_class_vtable_full (domain, klass, &error);
1768 mono_error_cleanup (&error);
1773 * mono_class_vtable_full:
1774 * @domain: the application domain
1775 * @class: the class to initialize
1776 * @error set on failure.
1778 * VTables are domain specific because we create domain specific code, and
1779 * they contain the domain specific static class data.
1782 mono_class_vtable_full (MonoDomain *domain, MonoClass *klass, MonoError *error)
1784 MONO_REQ_GC_UNSAFE_MODE;
1786 MonoClassRuntimeInfo *runtime_info;
1788 mono_error_init (error);
1792 if (mono_class_has_failure (klass)) {
1793 mono_error_set_for_class_failure (error, klass);
1797 /* this check can be inlined in jitted code, too */
1798 runtime_info = klass->runtime_info;
1799 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1800 return runtime_info->domain_vtables [domain->domain_id];
1801 return mono_class_create_runtime_vtable (domain, klass, error);
1805 * mono_class_try_get_vtable:
1806 * @domain: the application domain
1807 * @class: the class to initialize
1809 * This function tries to get the associated vtable from @class if
1810 * it was already created.
1813 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *klass)
1815 MONO_REQ_GC_NEUTRAL_MODE;
1817 MonoClassRuntimeInfo *runtime_info;
1821 runtime_info = klass->runtime_info;
1822 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1823 return runtime_info->domain_vtables [domain->domain_id];
1828 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1830 MONO_REQ_GC_NEUTRAL_MODE;
1832 size_t alloc_offset;
1835 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1836 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1837 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1839 if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1840 g_assert ((imt_table_bytes & 7) == 4);
1847 return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1851 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error)
1853 MONO_REQ_GC_UNSAFE_MODE;
1856 MonoClassRuntimeInfo *runtime_info, *old_info;
1857 MonoClassField *field;
1859 int i, vtable_slots;
1860 size_t imt_table_bytes;
1862 guint32 vtable_size, class_size;
1864 gpointer *interface_offsets;
1866 mono_error_init (error);
1868 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1869 mono_domain_lock (domain);
1870 runtime_info = klass->runtime_info;
1871 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1872 mono_domain_unlock (domain);
1873 mono_loader_unlock ();
1874 return runtime_info->domain_vtables [domain->domain_id];
1876 if (!klass->inited || mono_class_has_failure (klass)) {
1877 if (!mono_class_init (klass) || mono_class_has_failure (klass)) {
1878 mono_domain_unlock (domain);
1879 mono_loader_unlock ();
1880 mono_error_set_for_class_failure (error, klass);
1885 /* Array types require that their element type be valid*/
1886 if (klass->byval_arg.type == MONO_TYPE_ARRAY || klass->byval_arg.type == MONO_TYPE_SZARRAY) {
1887 MonoClass *element_class = klass->element_class;
1888 if (!element_class->inited)
1889 mono_class_init (element_class);
1891 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1892 if (!mono_class_has_failure (element_class) && !element_class->vtable_size)
1893 mono_class_setup_vtable (element_class);
1895 if (mono_class_has_failure (element_class)) {
1896 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1897 if (!mono_class_has_failure (klass))
1898 mono_class_set_type_load_failure (klass, "");
1899 mono_domain_unlock (domain);
1900 mono_loader_unlock ();
1901 mono_error_set_for_class_failure (error, klass);
1907 * For some classes, mono_class_init () already computed klass->vtable_size, and
1908 * that is all that is needed because of the vtable trampolines.
1910 if (!klass->vtable_size)
1911 mono_class_setup_vtable (klass);
1913 if (mono_class_is_ginst (klass) && !klass->vtable)
1914 mono_class_check_vtable_constraints (klass, NULL);
1916 /* Initialize klass->has_finalize */
1917 mono_class_has_finalizer (klass);
1919 if (mono_class_has_failure (klass)) {
1920 mono_domain_unlock (domain);
1921 mono_loader_unlock ();
1922 mono_error_set_for_class_failure (error, klass);
1926 vtable_slots = klass->vtable_size;
1927 /* we add an additional vtable slot to store the pointer to static field data only when needed */
1928 class_size = mono_class_data_size (klass);
1932 if (klass->interface_offsets_count) {
1933 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1934 mono_stats.imt_number_of_tables++;
1935 mono_stats.imt_tables_size += imt_table_bytes;
1937 imt_table_bytes = 0;
1940 vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
1942 mono_stats.used_class_count++;
1943 mono_stats.class_vtable_size += vtable_size;
1945 interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
1946 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1947 g_assert (!((gsize)vt & 7));
1950 vt->rank = klass->rank;
1951 vt->domain = domain;
1953 mono_class_compute_gc_descriptor (klass);
1955 * We can't use typed allocation in the non-root domains, since the
1956 * collector needs the GC descriptor stored in the vtable even after
1957 * the mempool containing the vtable is destroyed when the domain is
1958 * unloaded. An alternative might be to allocate vtables in the GC
1959 * heap, but this does not seem to work (it leads to crashes inside
1960 * libgc). If that approach is tried, two gc descriptors need to be
1961 * allocated for each class: one for the root domain, and one for all
1962 * other domains. The second descriptor should contain a bit for the
1963 * vtable field in MonoObject, since we can no longer assume the
1964 * vtable is reachable by other roots after the appdomain is unloaded.
1966 #ifdef HAVE_BOEHM_GC
1967 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1968 vt->gc_descr = MONO_GC_DESCRIPTOR_NULL;
1971 vt->gc_descr = klass->gc_descr;
1973 gc_bits = mono_gc_get_vtable_bits (klass);
1974 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
1976 vt->gc_bits = gc_bits;
1979 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
1980 if (klass->has_static_refs) {
1981 MonoGCDescriptor statics_gc_descr;
1983 gsize default_bitmap [4] = {0};
1986 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1987 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], klass->name_space, klass->name, class_size);*/
1988 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1989 vt->vtable [klass->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr, MONO_ROOT_SOURCE_STATIC, "managed static variables");
1990 mono_domain_add_class_static_data (domain, klass, vt->vtable [klass->vtable_size], NULL);
1991 if (bitmap != default_bitmap)
1994 vt->vtable [klass->vtable_size] = mono_domain_alloc0 (domain, class_size);
1996 vt->has_static_fields = TRUE;
1997 mono_stats.class_static_data_size += class_size;
2001 while ((field = mono_class_get_fields (klass, &iter))) {
2002 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2004 if (mono_field_is_deleted (field))
2006 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2007 gint32 special_static = klass->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (klass, field);
2008 if (special_static != SPECIAL_STATIC_NONE) {
2009 guint32 size, offset;
2011 gsize default_bitmap [4] = {0};
2016 if (mono_type_is_reference (field->type)) {
2017 default_bitmap [0] = 1;
2019 bitmap = default_bitmap;
2020 } else if (mono_type_is_struct (field->type)) {
2021 fclass = mono_class_from_mono_type (field->type);
2022 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
2023 numbits = max_set + 1;
2025 default_bitmap [0] = 0;
2027 bitmap = default_bitmap;
2029 size = mono_type_size (field->type, &align);
2030 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
2031 if (!domain->special_static_fields)
2032 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2033 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2034 if (bitmap != default_bitmap)
2037 * This marks the field as special static to speed up the
2038 * checks in mono_field_static_get/set_value ().
2044 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2045 MonoClass *fklass = mono_class_from_mono_type (field->type);
2046 const char *data = mono_field_get_data (field);
2048 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2049 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2050 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2053 if (fklass->valuetype) {
2054 memcpy (t, data, mono_class_value_size (fklass, NULL));
2056 /* it's a pointer type: add check */
2057 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2064 vt->max_interface_id = klass->max_interface_id;
2065 vt->interface_bitmap = klass->interface_bitmap;
2067 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2068 // class->name, klass->interface_offsets_count);
2070 /* Initialize vtable */
2071 if (callbacks.get_vtable_trampoline) {
2072 // This also covers the AOT case
2073 for (i = 0; i < klass->vtable_size; ++i) {
2074 vt->vtable [i] = callbacks.get_vtable_trampoline (vt, i);
2077 mono_class_setup_vtable (klass);
2079 for (i = 0; i < klass->vtable_size; ++i) {
2082 cm = klass->vtable [i];
2084 vt->vtable [i] = callbacks.create_jit_trampoline (domain, cm, error);
2085 if (!is_ok (error)) {
2086 mono_domain_unlock (domain);
2087 mono_loader_unlock ();
2094 if (imt_table_bytes) {
2095 /* Now that the vtable is full, we can actually fill up the IMT */
2096 for (i = 0; i < MONO_IMT_SIZE; ++i)
2097 interface_offsets [i] = callbacks.get_imt_trampoline (vt, i);
2101 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2102 * re-acquire them and check if another thread has created the vtable in the meantime.
2104 /* Special case System.MonoType to avoid infinite recursion */
2105 if (klass != mono_defaults.runtimetype_class) {
2106 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2107 if (!is_ok (error)) {
2108 mono_domain_unlock (domain);
2109 mono_loader_unlock ();
2113 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2114 /* This is unregistered in
2115 unregister_vtable_reflection_type() in
2117 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2120 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (klass));
2122 /* class_vtable_array keeps an array of created vtables
2124 g_ptr_array_add (domain->class_vtable_array, vt);
2125 /* klass->runtime_info is protected by the loader lock, both when
2126 * it it enlarged and when it is stored info.
2130 * Store the vtable in klass->runtime_info.
2131 * klass->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2133 mono_memory_barrier ();
2135 old_info = klass->runtime_info;
2136 if (old_info && old_info->max_domain >= domain->domain_id) {
2137 /* someone already created a large enough runtime info */
2138 old_info->domain_vtables [domain->domain_id] = vt;
2140 int new_size = domain->domain_id;
2142 new_size = MAX (new_size, old_info->max_domain);
2144 /* make the new size a power of two */
2146 while (new_size > i)
2149 /* this is a bounded memory retention issue: may want to
2150 * handle it differently when we'll have a rcu-like system.
2152 runtime_info = (MonoClassRuntimeInfo *)mono_image_alloc0 (klass->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2153 runtime_info->max_domain = new_size - 1;
2154 /* copy the stuff from the older info */
2156 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2158 runtime_info->domain_vtables [domain->domain_id] = vt;
2160 mono_memory_barrier ();
2161 klass->runtime_info = runtime_info;
2164 if (klass == mono_defaults.runtimetype_class) {
2165 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2166 if (!is_ok (error)) {
2167 mono_domain_unlock (domain);
2168 mono_loader_unlock ();
2172 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2173 /* This is unregistered in
2174 unregister_vtable_reflection_type() in
2176 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2179 mono_domain_unlock (domain);
2180 mono_loader_unlock ();
2182 /* make sure the parent is initialized */
2183 /*FIXME shouldn't this fail the current type?*/
2185 mono_class_vtable_full (domain, klass->parent, error);
2190 #ifndef DISABLE_REMOTING
2192 * mono_class_proxy_vtable:
2193 * @domain: the application domain
2194 * @remove_class: the remote class
2195 * @error: set on error
2197 * Creates a vtable for transparent proxies. It is basically
2198 * a copy of the real vtable of the class wrapped in @remote_class,
2199 * but all function pointers invoke the remoting functions, and
2200 * vtable->klass points to the transparent proxy class, and not to @class.
2202 * On failure returns NULL and sets @error
2205 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type, MonoError *error)
2207 MONO_REQ_GC_UNSAFE_MODE;
2209 MonoVTable *vt, *pvt;
2210 int i, j, vtsize, extra_interface_vtsize = 0;
2211 guint32 max_interface_id;
2213 GSList *extra_interfaces = NULL;
2214 MonoClass *klass = remote_class->proxy_class;
2215 gpointer *interface_offsets;
2216 uint8_t *bitmap = NULL;
2218 size_t imt_table_bytes;
2220 #ifdef COMPRESSED_INTERFACE_BITMAP
2224 mono_error_init (error);
2226 vt = mono_class_vtable (domain, klass);
2227 g_assert (vt); /*FIXME property handle failure*/
2228 max_interface_id = vt->max_interface_id;
2230 /* Calculate vtable space for extra interfaces */
2231 for (j = 0; j < remote_class->interface_count; j++) {
2232 MonoClass* iclass = remote_class->interfaces[j];
2236 /*FIXME test for interfaces with variant generic arguments*/
2237 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, iclass->interface_id))
2238 continue; /* interface implemented by the class */
2239 if (g_slist_find (extra_interfaces, iclass))
2242 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2244 method_count = mono_class_num_methods (iclass);
2246 ifaces = mono_class_get_implemented_interfaces (iclass, error);
2250 for (i = 0; i < ifaces->len; ++i) {
2251 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2252 /*FIXME test for interfaces with variant generic arguments*/
2253 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, ic->interface_id))
2254 continue; /* interface implemented by the class */
2255 if (g_slist_find (extra_interfaces, ic))
2257 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2258 method_count += mono_class_num_methods (ic);
2260 g_ptr_array_free (ifaces, TRUE);
2264 extra_interface_vtsize += method_count * sizeof (gpointer);
2265 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2268 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2269 mono_stats.imt_number_of_tables++;
2270 mono_stats.imt_tables_size += imt_table_bytes;
2272 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer);
2274 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2276 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2277 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2278 g_assert (!((gsize)pvt & 7));
2280 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer));
2282 pvt->klass = mono_defaults.transparent_proxy_class;
2283 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2284 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2286 /* initialize vtable */
2287 mono_class_setup_vtable (klass);
2288 for (i = 0; i < klass->vtable_size; ++i) {
2291 if ((cm = klass->vtable [i])) {
2292 pvt->vtable [i] = create_remoting_trampoline (domain, cm, target_type, error);
2296 pvt->vtable [i] = NULL;
2299 if (mono_class_is_abstract (klass)) {
2300 /* create trampolines for abstract methods */
2301 for (k = klass; k; k = k->parent) {
2303 gpointer iter = NULL;
2304 while ((m = mono_class_get_methods (k, &iter)))
2305 if (!pvt->vtable [m->slot]) {
2306 pvt->vtable [m->slot] = create_remoting_trampoline (domain, m, target_type, error);
2313 pvt->max_interface_id = max_interface_id;
2314 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2315 #ifdef COMPRESSED_INTERFACE_BITMAP
2316 bitmap = (uint8_t *)g_malloc0 (bsize);
2318 bitmap = (uint8_t *)mono_domain_alloc0 (domain, bsize);
2321 for (i = 0; i < klass->interface_offsets_count; ++i) {
2322 int interface_id = klass->interfaces_packed [i]->interface_id;
2323 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2326 if (extra_interfaces) {
2327 int slot = klass->vtable_size;
2333 /* Create trampolines for the methods of the interfaces */
2334 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2335 interf = (MonoClass *)list_item->data;
2337 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2341 while ((cm = mono_class_get_methods (interf, &iter))) {
2342 pvt->vtable [slot + j++] = create_remoting_trampoline (domain, cm, target_type, error);
2347 slot += mono_class_num_methods (interf);
2351 /* Now that the vtable is full, we can actually fill up the IMT */
2352 build_imt (klass, pvt, domain, interface_offsets, extra_interfaces);
2353 if (extra_interfaces) {
2354 g_slist_free (extra_interfaces);
2357 #ifdef COMPRESSED_INTERFACE_BITMAP
2358 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2359 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2360 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2363 pvt->interface_bitmap = bitmap;
2367 if (extra_interfaces)
2368 g_slist_free (extra_interfaces);
2369 #ifdef COMPRESSED_INTERFACE_BITMAP
2375 #endif /* DISABLE_REMOTING */
2378 * mono_class_field_is_special_static:
2380 * Returns whether @field is a thread/context static field.
2383 mono_class_field_is_special_static (MonoClassField *field)
2385 MONO_REQ_GC_NEUTRAL_MODE
2387 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2389 if (mono_field_is_deleted (field))
2391 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2392 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2399 * mono_class_field_get_special_static_type:
2400 * @field: The MonoClassField describing the field.
2402 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2403 * SPECIAL_STATIC_NONE otherwise.
2406 mono_class_field_get_special_static_type (MonoClassField *field)
2408 MONO_REQ_GC_NEUTRAL_MODE
2410 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2411 return SPECIAL_STATIC_NONE;
2412 if (mono_field_is_deleted (field))
2413 return SPECIAL_STATIC_NONE;
2414 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2415 return field_is_special_static (field->parent, field);
2416 return SPECIAL_STATIC_NONE;
2420 * mono_class_has_special_static_fields:
2422 * Returns whenever @klass has any thread/context static fields.
2425 mono_class_has_special_static_fields (MonoClass *klass)
2427 MONO_REQ_GC_NEUTRAL_MODE
2429 MonoClassField *field;
2433 while ((field = mono_class_get_fields (klass, &iter))) {
2434 g_assert (field->parent == klass);
2435 if (mono_class_field_is_special_static (field))
2442 #ifndef DISABLE_REMOTING
2444 * create_remote_class_key:
2445 * Creates an array of pointers that can be used as a hash key for a remote class.
2446 * The first element of the array is the number of pointers.
2449 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2451 MONO_REQ_GC_NEUTRAL_MODE;
2456 if (remote_class == NULL) {
2457 if (mono_class_is_interface (extra_class)) {
2458 key = (void **)g_malloc (sizeof(gpointer) * 3);
2459 key [0] = GINT_TO_POINTER (2);
2460 key [1] = mono_defaults.marshalbyrefobject_class;
2461 key [2] = extra_class;
2463 key = (void **)g_malloc (sizeof(gpointer) * 2);
2464 key [0] = GINT_TO_POINTER (1);
2465 key [1] = extra_class;
2468 if (extra_class != NULL && mono_class_is_interface (extra_class)) {
2469 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2470 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2471 key [1] = remote_class->proxy_class;
2473 // Keep the list of interfaces sorted
2474 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2475 if (extra_class && remote_class->interfaces [i] > extra_class) {
2476 key [j++] = extra_class;
2479 key [j] = remote_class->interfaces [i];
2482 key [j] = extra_class;
2484 // Replace the old class. The interface list is the same
2485 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2486 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2487 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2488 for (i = 0; i < remote_class->interface_count; i++)
2489 key [2 + i] = remote_class->interfaces [i];
2497 * copy_remote_class_key:
2499 * Make a copy of KEY in the domain and return the copy.
2502 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2504 MONO_REQ_GC_NEUTRAL_MODE
2506 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2507 gpointer *mp_key = (gpointer *)mono_domain_alloc (domain, key_size);
2509 memcpy (mp_key, key, key_size);
2515 * mono_remote_class:
2516 * @domain: the application domain
2517 * @class_name: name of the remote class
2518 * @error: set on error
2520 * Creates and initializes a MonoRemoteClass object for a remote type.
2522 * On failure returns NULL and sets @error
2525 mono_remote_class (MonoDomain *domain, MonoStringHandle class_name, MonoClass *proxy_class, MonoError *error)
2527 MONO_REQ_GC_UNSAFE_MODE;
2529 MonoRemoteClass *rc;
2530 gpointer* key, *mp_key;
2533 mono_error_init (error);
2535 key = create_remote_class_key (NULL, proxy_class);
2537 mono_domain_lock (domain);
2538 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2542 mono_domain_unlock (domain);
2546 name = mono_string_to_utf8_mp (domain->mp, MONO_HANDLE_RAW (class_name), error);
2547 if (!is_ok (error)) {
2549 mono_domain_unlock (domain);
2553 mp_key = copy_remote_class_key (domain, key);
2557 if (mono_class_is_interface (proxy_class)) {
2558 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2559 rc->interface_count = 1;
2560 rc->interfaces [0] = proxy_class;
2561 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2563 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2564 rc->interface_count = 0;
2565 rc->proxy_class = proxy_class;
2568 rc->default_vtable = NULL;
2569 rc->xdomain_vtable = NULL;
2570 rc->proxy_class_name = name;
2571 #ifndef DISABLE_PERFCOUNTERS
2572 mono_perfcounters->loader_bytes += mono_string_length (MONO_HANDLE_RAW (class_name)) + 1;
2575 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2577 mono_domain_unlock (domain);
2582 * clone_remote_class:
2583 * Creates a copy of the remote_class, adding the provided class or interface
2585 static MonoRemoteClass*
2586 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2588 MONO_REQ_GC_NEUTRAL_MODE;
2590 MonoRemoteClass *rc;
2591 gpointer* key, *mp_key;
2593 key = create_remote_class_key (remote_class, extra_class);
2594 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2600 mp_key = copy_remote_class_key (domain, key);
2604 if (mono_class_is_interface (extra_class)) {
2606 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2607 rc->proxy_class = remote_class->proxy_class;
2608 rc->interface_count = remote_class->interface_count + 1;
2610 // Keep the list of interfaces sorted, since the hash key of
2611 // the remote class depends on this
2612 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2613 if (remote_class->interfaces [i] > extra_class && i == j)
2614 rc->interfaces [j++] = extra_class;
2615 rc->interfaces [j] = remote_class->interfaces [i];
2618 rc->interfaces [j] = extra_class;
2620 // Replace the old class. The interface array is the same
2621 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2622 rc->proxy_class = extra_class;
2623 rc->interface_count = remote_class->interface_count;
2624 if (rc->interface_count > 0)
2625 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2628 rc->default_vtable = NULL;
2629 rc->xdomain_vtable = NULL;
2630 rc->proxy_class_name = remote_class->proxy_class_name;
2632 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2638 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxyHandle rp, MonoError *error)
2640 MONO_REQ_GC_UNSAFE_MODE;
2642 mono_error_init (error);
2644 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2645 mono_domain_lock (domain);
2646 gint32 target_domain_id = MONO_HANDLE_GETVAL (rp, target_domain_id);
2647 if (target_domain_id != -1) {
2648 if (remote_class->xdomain_vtable == NULL)
2649 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN, error);
2650 mono_domain_unlock (domain);
2651 mono_loader_unlock ();
2652 return_val_if_nok (error, NULL);
2653 return remote_class->xdomain_vtable;
2655 if (remote_class->default_vtable == NULL) {
2656 MonoReflectionTypeHandle reftype = MONO_HANDLE_NEW (MonoReflectionType, NULL);
2657 MONO_HANDLE_GET (reftype, rp, class_to_proxy);
2659 MonoType *type = MONO_HANDLE_GETVAL (reftype, type);
2660 MonoClass *klass = mono_class_from_mono_type (type);
2662 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)))
2663 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP, error);
2666 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN, error);
2667 /* N.B. both branches of the if modify error */
2668 if (!is_ok (error)) {
2669 mono_domain_unlock (domain);
2670 mono_loader_unlock ();
2675 mono_domain_unlock (domain);
2676 mono_loader_unlock ();
2677 return remote_class->default_vtable;
2681 * mono_upgrade_remote_class:
2682 * @domain: the application domain
2683 * @tproxy: the proxy whose remote class has to be upgraded.
2684 * @klass: class to which the remote class can be casted.
2685 * @error: set on error
2687 * Updates the vtable of the remote class by adding the necessary method slots
2688 * and interface offsets so it can be safely casted to klass. klass can be a
2689 * class or an interface. On success returns TRUE, on failure returns FALSE and sets @error.
2692 mono_upgrade_remote_class (MonoDomain *domain, MonoObjectHandle proxy_object, MonoClass *klass, MonoError *error)
2694 MONO_REQ_GC_UNSAFE_MODE;
2696 mono_error_init (error);
2698 MonoTransparentProxyHandle tproxy = MONO_HANDLE_CAST (MonoTransparentProxy, proxy_object);
2699 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (tproxy, remote_class);
2701 gboolean redo_vtable;
2702 if (mono_class_is_interface (klass)) {
2705 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2706 if (remote_class->interfaces [i] == klass)
2707 redo_vtable = FALSE;
2710 redo_vtable = (remote_class->proxy_class != klass);
2713 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2714 mono_domain_lock (domain);
2716 MonoRemoteClass *fresh_remote_class = clone_remote_class (domain, remote_class, klass);
2717 MONO_HANDLE_SETVAL (tproxy, remote_class, MonoRemoteClass*, fresh_remote_class);
2718 MonoRealProxyHandle real_proxy = MONO_HANDLE_NEW (MonoRealProxy, NULL);
2719 MONO_HANDLE_GET (real_proxy, tproxy, rp);
2720 MONO_HANDLE_SETVAL (proxy_object, vtable, MonoVTable*, mono_remote_class_vtable (domain, fresh_remote_class, real_proxy, error));
2726 mono_domain_unlock (domain);
2727 mono_loader_unlock ();
2728 return is_ok (error);
2730 #endif /* DISABLE_REMOTING */
2734 * mono_object_get_virtual_method:
2735 * @obj: object to operate on.
2738 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2739 * the instance of a callvirt of method.
2742 mono_object_get_virtual_method (MonoObject *obj_raw, MonoMethod *method)
2744 MONO_REQ_GC_UNSAFE_MODE;
2745 HANDLE_FUNCTION_ENTER ();
2747 MONO_HANDLE_DCL (MonoObject, obj);
2748 MonoMethod *result = mono_object_handle_get_virtual_method (obj, method, &error);
2749 mono_error_assert_ok (&error);
2750 HANDLE_FUNCTION_RETURN_VAL (result);
2754 * mono_object_get_virtual_method:
2755 * @obj: object to operate on.
2758 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2759 * the instance of a callvirt of method.
2762 mono_object_handle_get_virtual_method (MonoObjectHandle obj, MonoMethod *method, MonoError *error)
2764 mono_error_init (error);
2766 gboolean is_proxy = FALSE;
2767 MonoClass *klass = mono_handle_class (obj);
2768 if (mono_class_is_transparent_proxy (klass)) {
2769 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), remote_class);
2770 klass = remote_class->proxy_class;
2773 return class_get_virtual_method (klass, method, is_proxy, error);
2777 class_get_virtual_method (MonoClass *klass, MonoMethod *method, gboolean is_proxy, MonoError *error)
2779 mono_error_init (error);
2782 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2785 mono_class_setup_vtable (klass);
2786 MonoMethod **vtable = klass->vtable;
2788 if (method->slot == -1) {
2789 /* method->slot might not be set for instances of generic methods */
2790 if (method->is_inflated) {
2791 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2792 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2795 g_assert_not_reached ();
2799 MonoMethod *res = NULL;
2800 /* check method->slot is a valid index: perform isinstance? */
2801 if (method->slot != -1) {
2802 if (mono_class_is_interface (method->klass)) {
2804 gboolean variance_used = FALSE;
2805 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2806 g_assert (iface_offset > 0);
2807 res = vtable [iface_offset + method->slot];
2810 res = vtable [method->slot];
2814 #ifndef DISABLE_REMOTING
2816 /* It may be an interface, abstract class method or generic method */
2817 if (!res || mono_method_signature (res)->generic_param_count)
2820 /* generic methods demand invoke_with_check */
2821 if (mono_method_signature (res)->generic_param_count)
2822 res = mono_marshal_get_remoting_invoke_with_check (res);
2825 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2826 res = mono_cominterop_get_invoke (res);
2829 res = mono_marshal_get_remoting_invoke (res);
2834 if (method->is_inflated) {
2835 /* Have to inflate the result */
2836 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, error);
2844 do_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2846 MONO_REQ_GC_UNSAFE_MODE;
2848 MonoObject *result = NULL;
2850 g_assert (callbacks.runtime_invoke);
2852 mono_error_init (error);
2854 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2855 mono_profiler_method_start_invoke (method);
2857 result = callbacks.runtime_invoke (method, obj, params, exc, error);
2859 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2860 mono_profiler_method_end_invoke (method);
2862 if (!mono_error_ok (error))
2869 * mono_runtime_invoke:
2870 * @method: method to invoke
2871 * @obJ: object instance
2872 * @params: arguments to the method
2873 * @exc: exception information.
2875 * Invokes the method represented by @method on the object @obj.
2877 * obj is the 'this' pointer, it should be NULL for static
2878 * methods, a MonoObject* for object instances and a pointer to
2879 * the value type for value types.
2881 * The params array contains the arguments to the method with the
2882 * same convention: MonoObject* pointers for object instances and
2883 * pointers to the value type otherwise.
2885 * From unmanaged code you'll usually use the
2886 * mono_runtime_invoke() variant.
2888 * Note that this function doesn't handle virtual methods for
2889 * you, it will exec the exact method you pass: we still need to
2890 * expose a function to lookup the derived class implementation
2891 * of a virtual method (there are examples of this in the code,
2894 * You can pass NULL as the exc argument if you don't want to
2895 * catch exceptions, otherwise, *exc will be set to the exception
2896 * thrown, if any. if an exception is thrown, you can't use the
2897 * MonoObject* result from the function.
2899 * If the method returns a value type, it is boxed in an object
2903 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2908 res = mono_runtime_try_invoke (method, obj, params, exc, &error);
2909 if (*exc == NULL && !mono_error_ok(&error)) {
2910 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
2912 mono_error_cleanup (&error);
2914 res = mono_runtime_invoke_checked (method, obj, params, &error);
2915 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
2921 * mono_runtime_try_invoke:
2922 * @method: method to invoke
2923 * @obJ: object instance
2924 * @params: arguments to the method
2925 * @exc: exception information.
2926 * @error: set on error
2928 * Invokes the method represented by @method on the object @obj.
2930 * obj is the 'this' pointer, it should be NULL for static
2931 * methods, a MonoObject* for object instances and a pointer to
2932 * the value type for value types.
2934 * The params array contains the arguments to the method with the
2935 * same convention: MonoObject* pointers for object instances and
2936 * pointers to the value type otherwise.
2938 * From unmanaged code you'll usually use the
2939 * mono_runtime_invoke() variant.
2941 * Note that this function doesn't handle virtual methods for
2942 * you, it will exec the exact method you pass: we still need to
2943 * expose a function to lookup the derived class implementation
2944 * of a virtual method (there are examples of this in the code,
2947 * For this function, you must not pass NULL as the exc argument if
2948 * you don't want to catch exceptions, use
2949 * mono_runtime_invoke_checked(). If an exception is thrown, you
2950 * can't use the MonoObject* result from the function.
2952 * If this method cannot be invoked, @error will be set and @exc and
2953 * the return value must not be used.
2955 * If the method returns a value type, it is boxed in an object
2959 mono_runtime_try_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError* error)
2961 MONO_REQ_GC_UNSAFE_MODE;
2963 g_assert (exc != NULL);
2965 if (mono_runtime_get_no_exec ())
2966 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2968 return do_runtime_invoke (method, obj, params, exc, error);
2972 * mono_runtime_invoke_checked:
2973 * @method: method to invoke
2974 * @obJ: object instance
2975 * @params: arguments to the method
2976 * @error: set on error
2978 * Invokes the method represented by @method on the object @obj.
2980 * obj is the 'this' pointer, it should be NULL for static
2981 * methods, a MonoObject* for object instances and a pointer to
2982 * the value type for value types.
2984 * The params array contains the arguments to the method with the
2985 * same convention: MonoObject* pointers for object instances and
2986 * pointers to the value type otherwise.
2988 * From unmanaged code you'll usually use the
2989 * mono_runtime_invoke() variant.
2991 * Note that this function doesn't handle virtual methods for
2992 * you, it will exec the exact method you pass: we still need to
2993 * expose a function to lookup the derived class implementation
2994 * of a virtual method (there are examples of this in the code,
2997 * If an exception is thrown, you can't use the MonoObject* result
2998 * from the function.
3000 * If this method cannot be invoked, @error will be set. If the
3001 * method throws an exception (and we're in coop mode) the exception
3002 * will be set in @error.
3004 * If the method returns a value type, it is boxed in an object
3008 mono_runtime_invoke_checked (MonoMethod *method, void *obj, void **params, MonoError* error)
3010 MONO_REQ_GC_UNSAFE_MODE;
3012 if (mono_runtime_get_no_exec ())
3013 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
3015 return do_runtime_invoke (method, obj, params, NULL, error);
3019 * mono_method_get_unmanaged_thunk:
3020 * @method: method to generate a thunk for.
3022 * Returns an unmanaged->managed thunk that can be used to call
3023 * a managed method directly from C.
3025 * The thunk's C signature closely matches the managed signature:
3027 * C#: public bool Equals (object obj);
3028 * C: typedef MonoBoolean (*Equals)(MonoObject*,
3029 * MonoObject*, MonoException**);
3031 * The 1st ("this") parameter must not be used with static methods:
3033 * C#: public static bool ReferenceEquals (object a, object b);
3034 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
3037 * The last argument must be a non-null pointer of a MonoException* pointer.
3038 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
3039 * exception has been thrown in managed code. Otherwise it will point
3040 * to the MonoException* caught by the thunk. In this case, the result of
3041 * the thunk is undefined:
3043 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
3044 * MonoException *ex = NULL;
3045 * Equals func = mono_method_get_unmanaged_thunk (method);
3046 * MonoBoolean res = func (thisObj, objToCompare, &ex);
3048 * // handle exception
3051 * The calling convention of the thunk matches the platform's default
3052 * convention. This means that under Windows, C declarations must
3053 * contain the __stdcall attribute:
3055 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
3056 * MonoObject*, MonoException**);
3060 * Value type arguments and return values are treated as they were objects:
3062 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
3063 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
3065 * Arguments must be properly boxed upon trunk's invocation, while return
3066 * values must be unboxed.
3069 mono_method_get_unmanaged_thunk (MonoMethod *method)
3071 MONO_REQ_GC_NEUTRAL_MODE;
3072 MONO_REQ_API_ENTRYPOINT;
3077 g_assert (!mono_threads_is_coop_enabled ());
3079 MONO_ENTER_GC_UNSAFE;
3080 method = mono_marshal_get_thunk_invoke_wrapper (method);
3081 res = mono_compile_method_checked (method, &error);
3082 mono_error_cleanup (&error);
3083 MONO_EXIT_GC_UNSAFE;
3089 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
3091 MONO_REQ_GC_UNSAFE_MODE;
3095 /* object fields cannot be byref, so we don't need a
3097 gpointer *p = (gpointer*)dest;
3104 case MONO_TYPE_BOOLEAN:
3106 case MONO_TYPE_U1: {
3107 guint8 *p = (guint8*)dest;
3108 *p = value ? *(guint8*)value : 0;
3113 case MONO_TYPE_CHAR: {
3114 guint16 *p = (guint16*)dest;
3115 *p = value ? *(guint16*)value : 0;
3118 #if SIZEOF_VOID_P == 4
3123 case MONO_TYPE_U4: {
3124 gint32 *p = (gint32*)dest;
3125 *p = value ? *(gint32*)value : 0;
3128 #if SIZEOF_VOID_P == 8
3133 case MONO_TYPE_U8: {
3134 gint64 *p = (gint64*)dest;
3135 *p = value ? *(gint64*)value : 0;
3138 case MONO_TYPE_R4: {
3139 float *p = (float*)dest;
3140 *p = value ? *(float*)value : 0;
3143 case MONO_TYPE_R8: {
3144 double *p = (double*)dest;
3145 *p = value ? *(double*)value : 0;
3148 case MONO_TYPE_STRING:
3149 case MONO_TYPE_SZARRAY:
3150 case MONO_TYPE_CLASS:
3151 case MONO_TYPE_OBJECT:
3152 case MONO_TYPE_ARRAY:
3153 mono_gc_wbarrier_generic_store (dest, deref_pointer ? *(MonoObject **)value : (MonoObject *)value);
3155 case MONO_TYPE_FNPTR:
3156 case MONO_TYPE_PTR: {
3157 gpointer *p = (gpointer*)dest;
3158 *p = deref_pointer? *(gpointer*)value: value;
3161 case MONO_TYPE_VALUETYPE:
3162 /* note that 't' and 'type->type' can be different */
3163 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3164 t = mono_class_enum_basetype (type->data.klass)->type;
3167 MonoClass *klass = mono_class_from_mono_type (type);
3168 int size = mono_class_value_size (klass, NULL);
3170 mono_gc_bzero_atomic (dest, size);
3172 mono_gc_wbarrier_value_copy (dest, value, 1, klass);
3175 case MONO_TYPE_GENERICINST:
3176 t = type->data.generic_class->container_class->byval_arg.type;
3179 g_error ("got type %x", type->type);
3184 * mono_field_set_value:
3185 * @obj: Instance object
3186 * @field: MonoClassField describing the field to set
3187 * @value: The value to be set
3189 * Sets the value of the field described by @field in the object instance @obj
3190 * to the value passed in @value. This method should only be used for instance
3191 * fields. For static fields, use mono_field_static_set_value.
3193 * The value must be on the native format of the field type.
3196 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3198 MONO_REQ_GC_UNSAFE_MODE;
3202 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3204 dest = (char*)obj + field->offset;
3205 mono_copy_value (field->type, dest, value, FALSE);
3209 * mono_field_static_set_value:
3210 * @field: MonoClassField describing the field to set
3211 * @value: The value to be set
3213 * Sets the value of the static field described by @field
3214 * to the value passed in @value.
3216 * The value must be on the native format of the field type.
3219 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3221 MONO_REQ_GC_UNSAFE_MODE;
3225 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3226 /* you cant set a constant! */
3227 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3229 if (field->offset == -1) {
3230 /* Special static */
3233 mono_domain_lock (vt->domain);
3234 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3235 mono_domain_unlock (vt->domain);
3236 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3238 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3240 mono_copy_value (field->type, dest, value, FALSE);
3244 * mono_vtable_get_static_field_data:
3246 * Internal use function: return a pointer to the memory holding the static fields
3247 * for a class or NULL if there are no static fields.
3248 * This is exported only for use by the debugger.
3251 mono_vtable_get_static_field_data (MonoVTable *vt)
3253 MONO_REQ_GC_NEUTRAL_MODE
3255 if (!vt->has_static_fields)
3257 return vt->vtable [vt->klass->vtable_size];
3261 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3263 MONO_REQ_GC_UNSAFE_MODE;
3267 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3268 if (field->offset == -1) {
3269 /* Special static */
3272 mono_domain_lock (vt->domain);
3273 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3274 mono_domain_unlock (vt->domain);
3275 src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3277 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3280 src = (guint8*)obj + field->offset;
3287 * mono_field_get_value:
3288 * @obj: Object instance
3289 * @field: MonoClassField describing the field to fetch information from
3290 * @value: pointer to the location where the value will be stored
3292 * Use this routine to get the value of the field @field in the object
3295 * The pointer provided by value must be of the field type, for reference
3296 * types this is a MonoObject*, for value types its the actual pointer to
3301 * mono_field_get_value (obj, int_field, &i);
3304 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3306 MONO_REQ_GC_UNSAFE_MODE;
3312 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3314 src = (char*)obj + field->offset;
3315 mono_copy_value (field->type, value, src, TRUE);
3319 * mono_field_get_value_object:
3320 * @domain: domain where the object will be created (if boxing)
3321 * @field: MonoClassField describing the field to fetch information from
3322 * @obj: The object instance for the field.
3324 * Returns: a new MonoObject with the value from the given field. If the
3325 * field represents a value type, the value is boxed.
3329 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3332 MonoObject* result = mono_field_get_value_object_checked (domain, field, obj, &error);
3333 mono_error_assert_ok (&error);
3338 * mono_field_get_value_object_checked:
3339 * @domain: domain where the object will be created (if boxing)
3340 * @field: MonoClassField describing the field to fetch information from
3341 * @obj: The object instance for the field.
3342 * @error: Set on error.
3344 * Returns: a new MonoObject with the value from the given field. If the
3345 * field represents a value type, the value is boxed. On error returns NULL and sets @error.
3349 mono_field_get_value_object_checked (MonoDomain *domain, MonoClassField *field, MonoObject *obj, MonoError *error)
3351 MONO_REQ_GC_UNSAFE_MODE;
3353 mono_error_init (error);
3357 MonoVTable *vtable = NULL;
3359 gboolean is_static = FALSE;
3360 gboolean is_ref = FALSE;
3361 gboolean is_literal = FALSE;
3362 gboolean is_ptr = FALSE;
3363 MonoType *type = mono_field_get_type_checked (field, error);
3365 return_val_if_nok (error, NULL);
3367 switch (type->type) {
3368 case MONO_TYPE_STRING:
3369 case MONO_TYPE_OBJECT:
3370 case MONO_TYPE_CLASS:
3371 case MONO_TYPE_ARRAY:
3372 case MONO_TYPE_SZARRAY:
3377 case MONO_TYPE_BOOLEAN:
3380 case MONO_TYPE_CHAR:
3389 case MONO_TYPE_VALUETYPE:
3390 is_ref = type->byref;
3392 case MONO_TYPE_GENERICINST:
3393 is_ref = !mono_type_generic_inst_is_valuetype (type);
3399 g_error ("type 0x%x not handled in "
3400 "mono_field_get_value_object", type->type);
3404 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3407 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3411 vtable = mono_class_vtable_full (domain, field->parent, error);
3412 return_val_if_nok (error, NULL);
3414 if (!vtable->initialized) {
3415 mono_runtime_class_init_full (vtable, error);
3416 return_val_if_nok (error, NULL);
3425 get_default_field_value (domain, field, &o, error);
3426 return_val_if_nok (error, NULL);
3427 } else if (is_static) {
3428 mono_field_static_get_value_checked (vtable, field, &o, error);
3429 return_val_if_nok (error, NULL);
3431 mono_field_get_value (obj, field, &o);
3437 static MonoMethod *m;
3443 MonoClass *ptr_klass = mono_class_get_pointer_class ();
3444 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
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);
3459 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3460 args [0] = ptr ? *ptr : NULL;
3461 args [1] = mono_type_get_object_checked (mono_domain_get (), type, error);
3462 return_val_if_nok (error, NULL);
3464 o = mono_runtime_invoke_checked (m, NULL, args, error);
3465 return_val_if_nok (error, NULL);
3470 /* boxed value type */
3471 klass = mono_class_from_mono_type (type);
3473 if (mono_class_is_nullable (klass))
3474 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass, error);
3476 o = mono_object_new_checked (domain, klass, error);
3477 return_val_if_nok (error, NULL);
3478 v = ((gchar *) o) + sizeof (MonoObject);
3481 get_default_field_value (domain, field, v, error);
3482 return_val_if_nok (error, NULL);
3483 } else if (is_static) {
3484 mono_field_static_get_value_checked (vtable, field, v, error);
3485 return_val_if_nok (error, NULL);
3487 mono_field_get_value (obj, field, v);
3494 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value, MonoError *error)
3496 MONO_REQ_GC_UNSAFE_MODE;
3498 mono_error_init (error);
3500 const char *p = blob;
3501 mono_metadata_decode_blob_size (p, &p);
3504 case MONO_TYPE_BOOLEAN:
3507 *(guint8 *) value = *p;
3509 case MONO_TYPE_CHAR:
3512 *(guint16*) value = read16 (p);
3516 *(guint32*) value = read32 (p);
3520 *(guint64*) value = read64 (p);
3523 readr4 (p, (float*) value);
3526 readr8 (p, (double*) value);
3528 case MONO_TYPE_STRING:
3529 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob, error);
3531 case MONO_TYPE_CLASS:
3532 *(gpointer*) value = NULL;
3536 g_warning ("type 0x%02x should not be in constant table", type);
3542 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error)
3544 MONO_REQ_GC_NEUTRAL_MODE;
3546 MonoTypeEnum def_type;
3549 mono_error_init (error);
3551 data = mono_class_get_field_default_value (field, &def_type);
3552 mono_get_constant_value_from_blob (domain, def_type, data, value, error);
3556 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3558 MONO_REQ_GC_UNSAFE_MODE;
3562 mono_error_init (error);
3564 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3566 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3567 get_default_field_value (vt->domain, field, value, error);
3571 if (field->offset == -1) {
3572 /* Special static */
3573 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3574 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3576 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3578 mono_copy_value (field->type, value, src, TRUE);
3582 * mono_field_static_get_value:
3583 * @vt: vtable to the object
3584 * @field: MonoClassField describing the field to fetch information from
3585 * @value: where the value is returned
3587 * Use this routine to get the value of the static field @field value.
3589 * The pointer provided by value must be of the field type, for reference
3590 * types this is a MonoObject*, for value types its the actual pointer to
3595 * mono_field_static_get_value (vt, int_field, &i);
3598 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3600 MONO_REQ_GC_NEUTRAL_MODE;
3603 mono_field_static_get_value_checked (vt, field, value, &error);
3604 mono_error_cleanup (&error);
3608 * mono_field_static_get_value_checked:
3609 * @vt: vtable to the object
3610 * @field: MonoClassField describing the field to fetch information from
3611 * @value: where the value is returned
3612 * @error: set on error
3614 * Use this routine to get the value of the static field @field value.
3616 * The pointer provided by value must be of the field type, for reference
3617 * types this is a MonoObject*, for value types its the actual pointer to
3622 * mono_field_static_get_value_checked (vt, int_field, &i, error);
3623 * if (!is_ok (error)) { ... }
3625 * On failure sets @error.
3628 mono_field_static_get_value_checked (MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3630 MONO_REQ_GC_NEUTRAL_MODE;
3632 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value, error);
3636 * mono_property_set_value:
3637 * @prop: MonoProperty to set
3638 * @obj: instance object on which to act
3639 * @params: parameters to pass to the propery
3640 * @exc: optional exception
3642 * Invokes the property's set method with the given arguments on the
3643 * object instance obj (or NULL for static properties).
3645 * You can pass NULL as the exc argument if you don't want to
3646 * catch exceptions, otherwise, *exc will be set to the exception
3647 * thrown, if any. if an exception is thrown, you can't use the
3648 * MonoObject* result from the function.
3651 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3653 MONO_REQ_GC_UNSAFE_MODE;
3656 do_runtime_invoke (prop->set, obj, params, exc, &error);
3657 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3658 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3660 mono_error_cleanup (&error);
3665 * mono_property_set_value_checked:
3666 * @prop: MonoProperty to set
3667 * @obj: instance object on which to act
3668 * @params: parameters to pass to the propery
3669 * @error: set on error
3671 * Invokes the property's set method with the given arguments on the
3672 * object instance obj (or NULL for static properties).
3674 * Returns: TRUE on success. On failure returns FALSE and sets @error.
3675 * If an exception is thrown, it will be caught and returned via @error.
3678 mono_property_set_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3680 MONO_REQ_GC_UNSAFE_MODE;
3684 mono_error_init (error);
3685 do_runtime_invoke (prop->set, obj, params, &exc, error);
3686 if (exc != NULL && is_ok (error))
3687 mono_error_set_exception_instance (error, (MonoException*)exc);
3688 return is_ok (error);
3692 * mono_property_get_value:
3693 * @prop: MonoProperty to fetch
3694 * @obj: instance object on which to act
3695 * @params: parameters to pass to the propery
3696 * @exc: optional exception
3698 * Invokes the property's get method with the given arguments on the
3699 * object instance obj (or NULL for static properties).
3701 * You can pass NULL as the exc argument if you don't want to
3702 * catch exceptions, otherwise, *exc will be set to the exception
3703 * thrown, if any. if an exception is thrown, you can't use the
3704 * MonoObject* result from the function.
3706 * Returns: the value from invoking the get method on the property.
3709 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3711 MONO_REQ_GC_UNSAFE_MODE;
3714 MonoObject *val = do_runtime_invoke (prop->get, obj, params, exc, &error);
3715 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3716 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3718 mono_error_cleanup (&error); /* FIXME don't raise here */
3725 * mono_property_get_value_checked:
3726 * @prop: MonoProperty to fetch
3727 * @obj: instance object on which to act
3728 * @params: parameters to pass to the propery
3729 * @error: set on error
3731 * Invokes the property's get method with the given arguments on the
3732 * object instance obj (or NULL for static properties).
3734 * If an exception is thrown, you can't use the
3735 * MonoObject* result from the function. The exception will be propagated via @error.
3737 * Returns: the value from invoking the get method on the property. On
3738 * failure returns NULL and sets @error.
3741 mono_property_get_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3743 MONO_REQ_GC_UNSAFE_MODE;
3746 MonoObject *val = do_runtime_invoke (prop->get, obj, params, &exc, error);
3747 if (exc != NULL && !is_ok (error))
3748 mono_error_set_exception_instance (error, (MonoException*) exc);
3756 * mono_nullable_init:
3757 * @buf: The nullable structure to initialize.
3758 * @value: the value to initialize from
3759 * @klass: the type for the object
3761 * Initialize the nullable structure pointed to by @buf from @value which
3762 * should be a boxed value type. The size of @buf should be able to hold
3763 * as much data as the @klass->instance_size (which is the number of bytes
3764 * that will be copies).
3766 * Since Nullables have variable structure, we can not define a C
3767 * structure for them.
3770 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3772 MONO_REQ_GC_UNSAFE_MODE;
3774 MonoClass *param_class = klass->cast_class;
3776 mono_class_setup_fields (klass);
3777 g_assert (klass->fields_inited);
3779 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3780 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3782 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3784 if (param_class->has_references)
3785 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3787 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3789 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3794 * mono_nullable_box:
3795 * @buf: The buffer representing the data to be boxed
3796 * @klass: the type to box it as.
3797 * @error: set on oerr
3799 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3800 * @buf. On failure returns NULL and sets @error
3803 mono_nullable_box (guint8 *buf, MonoClass *klass, MonoError *error)
3805 MONO_REQ_GC_UNSAFE_MODE;
3807 mono_error_init (error);
3808 MonoClass *param_class = klass->cast_class;
3810 mono_class_setup_fields (klass);
3811 g_assert (klass->fields_inited);
3813 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3814 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3816 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3817 MonoObject *o = mono_object_new_checked (mono_domain_get (), param_class, error);
3818 return_val_if_nok (error, NULL);
3819 if (param_class->has_references)
3820 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3822 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3830 * mono_get_delegate_invoke:
3831 * @klass: The delegate class
3833 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3836 mono_get_delegate_invoke (MonoClass *klass)
3838 MONO_REQ_GC_NEUTRAL_MODE;
3842 /* This is called at runtime, so avoid the slower search in metadata */
3843 mono_class_setup_methods (klass);
3844 if (mono_class_has_failure (klass))
3846 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3851 * mono_get_delegate_begin_invoke:
3852 * @klass: The delegate class
3854 * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3857 mono_get_delegate_begin_invoke (MonoClass *klass)
3859 MONO_REQ_GC_NEUTRAL_MODE;
3863 /* This is called at runtime, so avoid the slower search in metadata */
3864 mono_class_setup_methods (klass);
3865 if (mono_class_has_failure (klass))
3867 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3872 * mono_get_delegate_end_invoke:
3873 * @klass: The delegate class
3875 * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3878 mono_get_delegate_end_invoke (MonoClass *klass)
3880 MONO_REQ_GC_NEUTRAL_MODE;
3884 /* This is called at runtime, so avoid the slower search in metadata */
3885 mono_class_setup_methods (klass);
3886 if (mono_class_has_failure (klass))
3888 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3893 * mono_runtime_delegate_invoke:
3894 * @delegate: pointer to a delegate object.
3895 * @params: parameters for the delegate.
3896 * @exc: Pointer to the exception result.
3898 * Invokes the delegate method @delegate with the parameters provided.
3900 * You can pass NULL as the exc argument if you don't want to
3901 * catch exceptions, otherwise, *exc will be set to the exception
3902 * thrown, if any. if an exception is thrown, you can't use the
3903 * MonoObject* result from the function.
3906 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3908 MONO_REQ_GC_UNSAFE_MODE;
3912 MonoObject *result = mono_runtime_delegate_try_invoke (delegate, params, exc, &error);
3914 mono_error_cleanup (&error);
3917 if (!is_ok (&error))
3918 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
3922 MonoObject *result = mono_runtime_delegate_invoke_checked (delegate, params, &error);
3923 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
3929 * mono_runtime_delegate_try_invoke:
3930 * @delegate: pointer to a delegate object.
3931 * @params: parameters for the delegate.
3932 * @exc: Pointer to the exception result.
3933 * @error: set on error
3935 * Invokes the delegate method @delegate with the parameters provided.
3937 * You can pass NULL as the exc argument if you don't want to
3938 * catch exceptions, otherwise, *exc will be set to the exception
3939 * thrown, if any. On failure to execute, @error will be set.
3940 * if an exception is thrown, you can't use the
3941 * MonoObject* result from the function.
3944 mono_runtime_delegate_try_invoke (MonoObject *delegate, void **params, MonoObject **exc, MonoError *error)
3946 MONO_REQ_GC_UNSAFE_MODE;
3948 mono_error_init (error);
3950 MonoClass *klass = delegate->vtable->klass;
3953 im = mono_get_delegate_invoke (klass);
3955 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3958 o = mono_runtime_try_invoke (im, delegate, params, exc, error);
3960 o = mono_runtime_invoke_checked (im, delegate, params, error);
3967 * mono_runtime_delegate_invoke_checked:
3968 * @delegate: pointer to a delegate object.
3969 * @params: parameters for the delegate.
3970 * @error: set on error
3972 * Invokes the delegate method @delegate with the parameters provided.
3974 * On failure @error will be set and you can't use the MonoObject*
3975 * result from the function.
3978 mono_runtime_delegate_invoke_checked (MonoObject *delegate, void **params, MonoError *error)
3980 mono_error_init (error);
3981 return mono_runtime_delegate_try_invoke (delegate, params, NULL, error);
3984 static char **main_args = NULL;
3985 static int num_main_args = 0;
3988 * mono_runtime_get_main_args:
3990 * Returns: a MonoArray with the arguments passed to the main program
3993 mono_runtime_get_main_args (void)
3995 MONO_REQ_GC_UNSAFE_MODE;
3997 MonoArray *result = mono_runtime_get_main_args_checked (&error);
3998 mono_error_assert_ok (&error);
4003 * mono_runtime_get_main_args:
4004 * @error: set on error
4006 * Returns: a MonoArray with the arguments passed to the main
4007 * program. On failure returns NULL and sets @error.
4010 mono_runtime_get_main_args_checked (MonoError *error)
4014 MonoDomain *domain = mono_domain_get ();
4016 mono_error_init (error);
4018 res = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, num_main_args, error);
4019 return_val_if_nok (error, NULL);
4021 for (i = 0; i < num_main_args; ++i)
4022 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
4028 free_main_args (void)
4030 MONO_REQ_GC_NEUTRAL_MODE;
4034 for (i = 0; i < num_main_args; ++i)
4035 g_free (main_args [i]);
4042 * mono_runtime_set_main_args:
4043 * @argc: number of arguments from the command line
4044 * @argv: array of strings from the command line
4046 * Set the command line arguments from an embedding application that doesn't otherwise call
4047 * mono_runtime_run_main ().
4050 mono_runtime_set_main_args (int argc, char* argv[])
4052 MONO_REQ_GC_NEUTRAL_MODE;
4057 main_args = g_new0 (char*, argc);
4058 num_main_args = argc;
4060 for (i = 0; i < argc; ++i) {
4063 utf8_arg = mono_utf8_from_external (argv[i]);
4064 if (utf8_arg == NULL) {
4065 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
4066 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4070 main_args [i] = utf8_arg;
4077 * Prepare an array of arguments in order to execute a standard Main()
4078 * method (argc/argv contains the executable name). This method also
4079 * sets the command line argument value needed by System.Environment.
4083 prepare_run_main (MonoMethod *method, int argc, char *argv[])
4085 MONO_REQ_GC_UNSAFE_MODE;
4089 MonoArray *args = NULL;
4090 MonoDomain *domain = mono_domain_get ();
4091 gchar *utf8_fullpath;
4092 MonoMethodSignature *sig;
4094 g_assert (method != NULL);
4096 mono_thread_set_main (mono_thread_current ());
4098 main_args = g_new0 (char*, argc);
4099 num_main_args = argc;
4101 if (!g_path_is_absolute (argv [0])) {
4102 gchar *basename = g_path_get_basename (argv [0]);
4103 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
4107 utf8_fullpath = mono_utf8_from_external (fullpath);
4108 if(utf8_fullpath == NULL) {
4109 /* Printing the arg text will cause glib to
4110 * whinge about "Invalid UTF-8", but at least
4111 * its relevant, and shows the problem text
4114 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
4115 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4122 utf8_fullpath = mono_utf8_from_external (argv[0]);
4123 if(utf8_fullpath == NULL) {
4124 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
4125 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4130 main_args [0] = utf8_fullpath;
4132 for (i = 1; i < argc; ++i) {
4135 utf8_arg=mono_utf8_from_external (argv[i]);
4136 if(utf8_arg==NULL) {
4137 /* Ditto the comment about Invalid UTF-8 here */
4138 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
4139 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4143 main_args [i] = utf8_arg;
4148 sig = mono_method_signature (method);
4150 g_print ("Unable to load Main method.\n");
4154 if (sig->param_count) {
4155 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, argc, &error);
4156 mono_error_assert_ok (&error);
4157 for (i = 0; i < argc; ++i) {
4158 /* The encodings should all work, given that
4159 * we've checked all these args for the
4162 gchar *str = mono_utf8_from_external (argv [i]);
4163 MonoString *arg = mono_string_new (domain, str);
4164 mono_array_setref (args, i, arg);
4168 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, 0, &error);
4169 mono_error_assert_ok (&error);
4172 mono_assembly_set_main (method->klass->image->assembly);
4178 * mono_runtime_run_main:
4179 * @method: the method to start the application with (usually Main)
4180 * @argc: number of arguments from the command line
4181 * @argv: array of strings from the command line
4182 * @exc: excetption results
4184 * Execute a standard Main() method (argc/argv contains the
4185 * executable name). This method also sets the command line argument value
4186 * needed by System.Environment.
4191 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
4194 MONO_REQ_GC_UNSAFE_MODE;
4197 MonoArray *args = prepare_run_main (method, argc, argv);
4200 res = mono_runtime_try_exec_main (method, args, exc);
4202 res = mono_runtime_exec_main_checked (method, args, &error);
4203 mono_error_raise_exception (&error); /* OK to throw, external only without a better alternative */
4209 * mono_runtime_run_main_checked:
4210 * @method: the method to start the application with (usually Main)
4211 * @argc: number of arguments from the command line
4212 * @argv: array of strings from the command line
4213 * @error: set on error
4215 * Execute a standard Main() method (argc/argv contains the
4216 * executable name). This method also sets the command line argument value
4217 * needed by System.Environment. On failure sets @error.
4222 mono_runtime_run_main_checked (MonoMethod *method, int argc, char* argv[],
4225 mono_error_init (error);
4226 MonoArray *args = prepare_run_main (method, argc, argv);
4227 return mono_runtime_exec_main_checked (method, args, error);
4231 * mono_runtime_try_run_main:
4232 * @method: the method to start the application with (usually Main)
4233 * @argc: number of arguments from the command line
4234 * @argv: array of strings from the command line
4235 * @exc: set if Main throws an exception
4236 * @error: set if Main can't be executed
4238 * Execute a standard Main() method (argc/argv contains the executable
4239 * name). This method also sets the command line argument value needed
4240 * by System.Environment. On failure sets @error if Main can't be
4241 * executed or @exc if it threw and exception.
4246 mono_runtime_try_run_main (MonoMethod *method, int argc, char* argv[],
4250 MonoArray *args = prepare_run_main (method, argc, argv);
4251 return mono_runtime_try_exec_main (method, args, exc);
4256 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4258 static MonoMethod *serialize_method;
4264 if (!serialize_method) {
4265 MonoClass *klass = mono_class_get_remoting_services_class ();
4266 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
4269 if (!serialize_method) {
4274 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
4279 array = mono_runtime_try_invoke (serialize_method, NULL, params, exc, &error);
4280 if (*exc == NULL && !mono_error_ok (&error))
4281 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert serialize_object to MonoError */
4283 mono_error_cleanup (&error);
4292 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4294 MONO_REQ_GC_UNSAFE_MODE;
4296 static MonoMethod *deserialize_method;
4302 if (!deserialize_method) {
4303 MonoClass *klass = mono_class_get_remoting_services_class ();
4304 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
4306 if (!deserialize_method) {
4314 result = mono_runtime_try_invoke (deserialize_method, NULL, params, exc, &error);
4315 if (*exc == NULL && !mono_error_ok (&error))
4316 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert deserialize_object to MonoError */
4318 mono_error_cleanup (&error);
4326 #ifndef DISABLE_REMOTING
4328 make_transparent_proxy (MonoObject *obj, MonoError *error)
4330 MONO_REQ_GC_UNSAFE_MODE;
4332 static MonoMethod *get_proxy_method;
4334 MonoDomain *domain = mono_domain_get ();
4335 MonoRealProxy *real_proxy;
4336 MonoReflectionType *reflection_type;
4337 MonoTransparentProxy *transparent_proxy;
4339 mono_error_init (error);
4341 if (!get_proxy_method)
4342 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
4344 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
4346 real_proxy = (MonoRealProxy*) mono_object_new_checked (domain, mono_defaults.real_proxy_class, error);
4347 return_val_if_nok (error, NULL);
4348 reflection_type = mono_type_get_object_checked (domain, &obj->vtable->klass->byval_arg, error);
4349 return_val_if_nok (error, NULL);
4351 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
4352 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
4354 MonoObject *exc = NULL;
4356 transparent_proxy = (MonoTransparentProxy*) mono_runtime_try_invoke (get_proxy_method, real_proxy, NULL, &exc, error);
4357 if (exc != NULL && is_ok (error))
4358 mono_error_set_exception_instance (error, (MonoException*)exc);
4360 return (MonoObject*) transparent_proxy;
4362 #endif /* DISABLE_REMOTING */
4365 * mono_object_xdomain_representation
4367 * @target_domain: a domain
4368 * @error: set on error.
4370 * Creates a representation of obj in the domain target_domain. This
4371 * is either a copy of obj arrived through via serialization and
4372 * deserialization or a proxy, depending on whether the object is
4373 * serializable or marshal by ref. obj must not be in target_domain.
4375 * If the object cannot be represented in target_domain, NULL is
4376 * returned and @error is set appropriately.
4379 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoError *error)
4381 MONO_REQ_GC_UNSAFE_MODE;
4383 mono_error_init (error);
4384 MonoObject *deserialized = NULL;
4386 #ifndef DISABLE_REMOTING
4387 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
4388 deserialized = make_transparent_proxy (obj, error);
4393 gboolean failure = FALSE;
4394 MonoDomain *domain = mono_domain_get ();
4395 MonoObject *serialized;
4396 MonoObject *exc = NULL;
4398 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
4399 serialized = serialize_object (obj, &failure, &exc);
4400 mono_domain_set_internal_with_options (target_domain, FALSE);
4402 deserialized = deserialize_object (serialized, &failure, &exc);
4403 if (domain != target_domain)
4404 mono_domain_set_internal_with_options (domain, FALSE);
4406 mono_error_set_exception_instance (error, (MonoException*)exc);
4409 return deserialized;
4412 /* Used in call_unhandled_exception_delegate */
4414 create_unhandled_exception_eventargs (MonoObject *exc, MonoError *error)
4416 MONO_REQ_GC_UNSAFE_MODE;
4418 mono_error_init (error);
4421 MonoMethod *method = NULL;
4422 MonoBoolean is_terminating = TRUE;
4425 klass = mono_class_get_unhandled_exception_event_args_class ();
4426 mono_class_init (klass);
4428 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4429 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
4433 args [1] = &is_terminating;
4435 obj = mono_object_new_checked (mono_domain_get (), klass, error);
4436 return_val_if_nok (error, NULL);
4438 mono_runtime_invoke_checked (method, obj, args, error);
4439 return_val_if_nok (error, NULL);
4444 /* Used in mono_unhandled_exception */
4446 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4447 MONO_REQ_GC_UNSAFE_MODE;
4450 MonoObject *e = NULL;
4452 MonoDomain *current_domain = mono_domain_get ();
4454 if (domain != current_domain)
4455 mono_domain_set_internal_with_options (domain, FALSE);
4457 g_assert (domain == mono_object_domain (domain->domain));
4459 if (mono_object_domain (exc) != domain) {
4461 exc = mono_object_xdomain_representation (exc, domain, &error);
4463 if (!is_ok (&error)) {
4464 MonoError inner_error;
4465 MonoException *serialization_exc = mono_error_convert_to_exception (&error);
4466 exc = mono_object_xdomain_representation ((MonoObject*)serialization_exc, domain, &inner_error);
4467 mono_error_assert_ok (&inner_error);
4469 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4470 "System.Runtime.Serialization", "SerializationException",
4471 "Could not serialize unhandled exception.");
4475 g_assert (mono_object_domain (exc) == domain);
4477 pa [0] = domain->domain;
4478 pa [1] = create_unhandled_exception_eventargs (exc, &error);
4479 mono_error_assert_ok (&error);
4480 mono_runtime_delegate_try_invoke (delegate, pa, &e, &error);
4481 if (!is_ok (&error)) {
4483 e = (MonoObject*)mono_error_convert_to_exception (&error);
4485 mono_error_cleanup (&error);
4488 if (domain != current_domain)
4489 mono_domain_set_internal_with_options (current_domain, FALSE);
4492 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4493 if (!mono_error_ok (&error)) {
4494 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4495 mono_error_cleanup (&error);
4497 g_warning ("exception inside UnhandledException handler: %s\n", msg);
4503 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4506 * mono_runtime_unhandled_exception_policy_set:
4507 * @policy: the new policy
4509 * This is a VM internal routine.
4511 * Sets the runtime policy for handling unhandled exceptions.
4514 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4515 runtime_unhandled_exception_policy = policy;
4519 * mono_runtime_unhandled_exception_policy_get:
4521 * This is a VM internal routine.
4523 * Gets the runtime policy for handling unhandled exceptions.
4525 MonoRuntimeUnhandledExceptionPolicy
4526 mono_runtime_unhandled_exception_policy_get (void) {
4527 return runtime_unhandled_exception_policy;
4531 * mono_unhandled_exception:
4532 * @exc: exception thrown
4534 * This is a VM internal routine.
4536 * We call this function when we detect an unhandled exception
4537 * in the default domain.
4539 * It invokes the * UnhandledException event in AppDomain or prints
4540 * a warning to the console
4543 mono_unhandled_exception (MonoObject *exc)
4545 MONO_REQ_GC_UNSAFE_MODE;
4548 MonoClassField *field;
4549 MonoDomain *current_domain, *root_domain;
4550 MonoObject *current_appdomain_delegate = NULL, *root_appdomain_delegate = NULL;
4552 if (mono_class_has_parent (exc->vtable->klass, mono_defaults.threadabortexception_class))
4555 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4558 current_domain = mono_domain_get ();
4559 root_domain = mono_get_root_domain ();
4561 root_appdomain_delegate = mono_field_get_value_object_checked (root_domain, field, (MonoObject*) root_domain->domain, &error);
4562 mono_error_assert_ok (&error);
4563 if (current_domain != root_domain) {
4564 current_appdomain_delegate = mono_field_get_value_object_checked (current_domain, field, (MonoObject*) current_domain->domain, &error);
4565 mono_error_assert_ok (&error);
4568 if (!current_appdomain_delegate && !root_appdomain_delegate) {
4569 mono_print_unhandled_exception (exc);
4571 /* unhandled exception callbacks must not be aborted */
4572 mono_threads_begin_abort_protected_block ();
4573 if (root_appdomain_delegate)
4574 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4575 if (current_appdomain_delegate)
4576 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4577 mono_threads_end_abort_protected_block ();
4580 /* set exitcode only if we will abort the process */
4581 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4582 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4584 mono_environment_exitcode_set (1);
4589 * mono_runtime_exec_managed_code:
4590 * @domain: Application domain
4591 * @main_func: function to invoke from the execution thread
4592 * @main_args: parameter to the main_func
4594 * Launch a new thread to execute a function
4596 * main_func is called back from the thread with main_args as the
4597 * parameter. The callback function is expected to start Main()
4598 * eventually. This function then waits for all managed threads to
4600 * It is not necesseray anymore to execute managed code in a subthread,
4601 * so this function should not be used anymore by default: just
4602 * execute the code and then call mono_thread_manage ().
4605 mono_runtime_exec_managed_code (MonoDomain *domain,
4606 MonoMainThreadFunc main_func,
4610 mono_thread_create_checked (domain, main_func, main_args, &error);
4611 mono_error_assert_ok (&error);
4613 mono_thread_manage ();
4617 prepare_thread_to_exec_main (MonoDomain *domain, MonoMethod *method)
4619 MonoInternalThread* thread = mono_thread_internal_current ();
4620 MonoCustomAttrInfo* cinfo;
4621 gboolean has_stathread_attribute;
4623 if (!domain->entry_assembly) {
4625 MonoAssembly *assembly;
4627 assembly = method->klass->image->assembly;
4628 domain->entry_assembly = assembly;
4629 /* Domains created from another domain already have application_base and configuration_file set */
4630 if (domain->setup->application_base == NULL) {
4631 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4634 if (domain->setup->configuration_file == NULL) {
4635 str = g_strconcat (assembly->image->name, ".config", NULL);
4636 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4638 mono_domain_set_options_from_config (domain);
4642 MonoError cattr_error;
4643 cinfo = mono_custom_attrs_from_method_checked (method, &cattr_error);
4644 mono_error_cleanup (&cattr_error); /* FIXME warn here? */
4646 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, mono_class_get_sta_thread_attribute_class ());
4648 mono_custom_attrs_free (cinfo);
4650 has_stathread_attribute = FALSE;
4652 if (has_stathread_attribute) {
4653 thread->apartment_state = ThreadApartmentState_STA;
4655 thread->apartment_state = ThreadApartmentState_MTA;
4657 mono_thread_init_apartment_state ();
4662 do_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4664 MONO_REQ_GC_UNSAFE_MODE;
4669 mono_error_init (error);
4674 /* FIXME: check signature of method */
4675 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4677 res = mono_runtime_invoke_checked (method, NULL, pa, error);
4679 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4682 mono_environment_exitcode_set (rval);
4684 mono_runtime_invoke_checked (method, NULL, pa, error);
4696 do_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4698 MONO_REQ_GC_UNSAFE_MODE;
4708 /* FIXME: check signature of method */
4709 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4710 MonoError inner_error;
4712 res = mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4713 if (*exc == NULL && !mono_error_ok (&inner_error))
4714 *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4716 mono_error_cleanup (&inner_error);
4719 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4723 mono_environment_exitcode_set (rval);
4725 MonoError inner_error;
4726 mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4727 if (*exc == NULL && !mono_error_ok (&inner_error))
4728 *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4730 mono_error_cleanup (&inner_error);
4735 /* If the return type of Main is void, only
4736 * set the exitcode if an exception was thrown
4737 * (we don't want to blow away an
4738 * explicitly-set exit code)
4741 mono_environment_exitcode_set (rval);
4749 * Execute a standard Main() method (args doesn't contain the
4753 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4756 prepare_thread_to_exec_main (mono_object_domain (args), method);
4758 int rval = do_try_exec_main (method, args, exc);
4761 int rval = do_exec_main_checked (method, args, &error);
4762 mono_error_raise_exception (&error); /* OK to throw, external only with no better option */
4768 * Execute a standard Main() method (args doesn't contain the
4771 * On failure sets @error
4774 mono_runtime_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4776 mono_error_init (error);
4777 prepare_thread_to_exec_main (mono_object_domain (args), method);
4778 return do_exec_main_checked (method, args, error);
4782 * Execute a standard Main() method (args doesn't contain the
4785 * On failure sets @error if Main couldn't be executed, or @exc if it threw an exception.
4788 mono_runtime_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4790 prepare_thread_to_exec_main (mono_object_domain (args), method);
4791 return do_try_exec_main (method, args, exc);
4796 /** invoke_array_extract_argument:
4797 * @params: array of arguments to the method.
4798 * @i: the index of the argument to extract.
4799 * @t: ith type from the method signature.
4800 * @has_byref_nullables: outarg - TRUE if method expects a byref nullable argument
4801 * @error: set on error.
4803 * Given an array of method arguments, return the ith one using the corresponding type
4804 * to perform necessary unboxing. If method expects a ref nullable argument, writes TRUE to @has_byref_nullables.
4806 * On failure sets @error and returns NULL.
4809 invoke_array_extract_argument (MonoArray *params, int i, MonoType *t, gboolean* has_byref_nullables, MonoError *error)
4811 MonoType *t_orig = t;
4812 gpointer result = NULL;
4813 mono_error_init (error);
4818 case MONO_TYPE_BOOLEAN:
4821 case MONO_TYPE_CHAR:
4830 case MONO_TYPE_VALUETYPE:
4831 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (t_orig))) {
4832 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4833 result = mono_array_get (params, MonoObject*, i);
4835 *has_byref_nullables = TRUE;
4837 /* MS seems to create the objects if a null is passed in */
4838 if (!mono_array_get (params, MonoObject*, i)) {
4839 MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (t_orig), error);
4840 return_val_if_nok (error, NULL);
4841 mono_array_setref (params, i, o);
4846 * We can't pass the unboxed vtype byref to the callee, since
4847 * that would mean the callee would be able to modify boxed
4848 * primitive types. So we (and MS) make a copy of the boxed
4849 * object, pass that to the callee, and replace the original
4850 * boxed object in the arg array with the copy.
4852 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4853 MonoObject *copy = mono_value_box_checked (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig), error);
4854 return_val_if_nok (error, NULL);
4855 mono_array_setref (params, i, copy);
4858 result = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4861 case MONO_TYPE_STRING:
4862 case MONO_TYPE_OBJECT:
4863 case MONO_TYPE_CLASS:
4864 case MONO_TYPE_ARRAY:
4865 case MONO_TYPE_SZARRAY:
4867 result = mono_array_addr (params, MonoObject*, i);
4868 // FIXME: I need to check this code path
4870 result = mono_array_get (params, MonoObject*, i);
4872 case MONO_TYPE_GENERICINST:
4874 t = &t->data.generic_class->container_class->this_arg;
4876 t = &t->data.generic_class->container_class->byval_arg;
4878 case MONO_TYPE_PTR: {
4881 /* The argument should be an IntPtr */
4882 arg = mono_array_get (params, MonoObject*, i);
4886 g_assert (arg->vtable->klass == mono_defaults.int_class);
4887 result = ((MonoIntPtr*)arg)->m_value;
4892 g_error ("type 0x%x not handled in mono_runtime_invoke_array", t_orig->type);
4897 * mono_runtime_invoke_array:
4898 * @method: method to invoke
4899 * @obJ: object instance
4900 * @params: arguments to the method
4901 * @exc: exception information.
4903 * Invokes the method represented by @method on the object @obj.
4905 * obj is the 'this' pointer, it should be NULL for static
4906 * methods, a MonoObject* for object instances and a pointer to
4907 * the value type for value types.
4909 * The params array contains the arguments to the method with the
4910 * same convention: MonoObject* pointers for object instances and
4911 * pointers to the value type otherwise. The _invoke_array
4912 * variant takes a C# object[] as the params argument (MonoArray
4913 * *params): in this case the value types are boxed inside the
4914 * respective reference representation.
4916 * From unmanaged code you'll usually use the
4917 * mono_runtime_invoke_checked() variant.
4919 * Note that this function doesn't handle virtual methods for
4920 * you, it will exec the exact method you pass: we still need to
4921 * expose a function to lookup the derived class implementation
4922 * of a virtual method (there are examples of this in the code,
4925 * You can pass NULL as the exc argument if you don't want to
4926 * catch exceptions, otherwise, *exc will be set to the exception
4927 * thrown, if any. if an exception is thrown, you can't use the
4928 * MonoObject* result from the function.
4930 * If the method returns a value type, it is boxed in an object
4934 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4939 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, exc, &error);
4941 mono_error_cleanup (&error);
4944 if (!is_ok (&error))
4945 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
4949 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, NULL, &error);
4950 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
4956 * mono_runtime_invoke_array_checked:
4957 * @method: method to invoke
4958 * @obJ: object instance
4959 * @params: arguments to the method
4960 * @error: set on failure.
4962 * Invokes the method represented by @method on the object @obj.
4964 * obj is the 'this' pointer, it should be NULL for static
4965 * methods, a MonoObject* for object instances and a pointer to
4966 * the value type for value types.
4968 * The params array contains the arguments to the method with the
4969 * same convention: MonoObject* pointers for object instances and
4970 * pointers to the value type otherwise. The _invoke_array
4971 * variant takes a C# object[] as the params argument (MonoArray
4972 * *params): in this case the value types are boxed inside the
4973 * respective reference representation.
4975 * From unmanaged code you'll usually use the
4976 * mono_runtime_invoke_checked() variant.
4978 * Note that this function doesn't handle virtual methods for
4979 * you, it will exec the exact method you pass: we still need to
4980 * expose a function to lookup the derived class implementation
4981 * of a virtual method (there are examples of this in the code,
4984 * On failure or exception, @error will be set. In that case, you
4985 * can't use the MonoObject* result from the function.
4987 * If the method returns a value type, it is boxed in an object
4991 mono_runtime_invoke_array_checked (MonoMethod *method, void *obj, MonoArray *params,
4994 mono_error_init (error);
4995 return mono_runtime_try_invoke_array (method, obj, params, NULL, error);
4999 * mono_runtime_try_invoke_array:
5000 * @method: method to invoke
5001 * @obJ: object instance
5002 * @params: arguments to the method
5003 * @exc: exception information.
5004 * @error: set on failure.
5006 * Invokes the method represented by @method on the object @obj.
5008 * obj is the 'this' pointer, it should be NULL for static
5009 * methods, a MonoObject* for object instances and a pointer to
5010 * the value type for value types.
5012 * The params array contains the arguments to the method with the
5013 * same convention: MonoObject* pointers for object instances and
5014 * pointers to the value type otherwise. The _invoke_array
5015 * variant takes a C# object[] as the params argument (MonoArray
5016 * *params): in this case the value types are boxed inside the
5017 * respective reference representation.
5019 * From unmanaged code you'll usually use the
5020 * mono_runtime_invoke_checked() variant.
5022 * Note that this function doesn't handle virtual methods for
5023 * you, it will exec the exact method you pass: we still need to
5024 * expose a function to lookup the derived class implementation
5025 * of a virtual method (there are examples of this in the code,
5028 * You can pass NULL as the exc argument if you don't want to catch
5029 * exceptions, otherwise, *exc will be set to the exception thrown, if
5030 * any. On other failures, @error will be set. If an exception is
5031 * thrown or there's an error, you can't use the MonoObject* result
5032 * from the function.
5034 * If the method returns a value type, it is boxed in an object
5038 mono_runtime_try_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
5039 MonoObject **exc, MonoError *error)
5041 MONO_REQ_GC_UNSAFE_MODE;
5043 mono_error_init (error);
5045 MonoMethodSignature *sig = mono_method_signature (method);
5046 gpointer *pa = NULL;
5049 gboolean has_byref_nullables = FALSE;
5051 if (NULL != params) {
5052 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
5053 for (i = 0; i < mono_array_length (params); i++) {
5054 MonoType *t = sig->params [i];
5055 pa [i] = invoke_array_extract_argument (params, i, t, &has_byref_nullables, error);
5056 return_val_if_nok (error, NULL);
5060 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
5063 if (mono_class_is_nullable (method->klass)) {
5064 /* Need to create a boxed vtype instead */
5070 return mono_value_box_checked (mono_domain_get (), method->klass->cast_class, pa [0], error);
5075 obj = mono_object_new_checked (mono_domain_get (), method->klass, error);
5076 mono_error_assert_ok (error);
5077 g_assert (obj); /*maybe we should raise a TLE instead?*/
5078 #ifndef DISABLE_REMOTING
5079 if (mono_object_is_transparent_proxy (obj)) {
5080 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
5083 if (method->klass->valuetype)
5084 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
5087 } else if (method->klass->valuetype) {
5088 obj = mono_value_box_checked (mono_domain_get (), method->klass, obj, error);
5089 return_val_if_nok (error, NULL);
5093 mono_runtime_try_invoke (method, o, pa, exc, error);
5095 mono_runtime_invoke_checked (method, o, pa, error);
5098 return (MonoObject *)obj;
5100 if (mono_class_is_nullable (method->klass)) {
5101 MonoObject *nullable;
5103 /* Convert the unboxed vtype into a Nullable structure */
5104 nullable = mono_object_new_checked (mono_domain_get (), method->klass, error);
5105 return_val_if_nok (error, NULL);
5107 MonoObject *boxed = mono_value_box_checked (mono_domain_get (), method->klass->cast_class, obj, error);
5108 return_val_if_nok (error, NULL);
5109 mono_nullable_init ((guint8 *)mono_object_unbox (nullable), boxed, method->klass);
5110 obj = mono_object_unbox (nullable);
5113 /* obj must be already unboxed if needed */
5115 res = mono_runtime_try_invoke (method, obj, pa, exc, error);
5117 res = mono_runtime_invoke_checked (method, obj, pa, error);
5119 return_val_if_nok (error, NULL);
5121 if (sig->ret->type == MONO_TYPE_PTR) {
5122 MonoClass *pointer_class;
5123 static MonoMethod *box_method;
5125 MonoObject *box_exc;
5128 * The runtime-invoke wrapper returns a boxed IntPtr, need to
5129 * convert it to a Pointer object.
5131 pointer_class = mono_class_get_pointer_class ();
5133 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
5135 g_assert (res->vtable->klass == mono_defaults.int_class);
5136 box_args [0] = ((MonoIntPtr*)res)->m_value;
5137 box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, error);
5138 return_val_if_nok (error, NULL);
5140 res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, error);
5141 g_assert (box_exc == NULL);
5142 mono_error_assert_ok (error);
5145 if (has_byref_nullables) {
5147 * The runtime invoke wrapper already converted byref nullables back,
5148 * and stored them in pa, we just need to copy them back to the
5151 for (i = 0; i < mono_array_length (params); i++) {
5152 MonoType *t = sig->params [i];
5154 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
5155 mono_array_setref (params, i, pa [i]);
5165 * @klass: the class of the object that we want to create
5167 * Returns: a newly created object whose definition is
5168 * looked up using @klass. This will not invoke any constructors,
5169 * so the consumer of this routine has to invoke any constructors on
5170 * its own to initialize the object.
5172 * It returns NULL on failure.
5175 mono_object_new (MonoDomain *domain, MonoClass *klass)
5177 MONO_REQ_GC_UNSAFE_MODE;
5181 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5183 mono_error_cleanup (&error);
5188 ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
5190 MONO_REQ_GC_UNSAFE_MODE;
5194 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5196 mono_error_set_pending_exception (&error);
5201 * mono_object_new_checked:
5202 * @klass: the class of the object that we want to create
5203 * @error: set on error
5205 * Returns: a newly created object whose definition is
5206 * looked up using @klass. This will not invoke any constructors,
5207 * so the consumer of this routine has to invoke any constructors on
5208 * its own to initialize the object.
5210 * It returns NULL on failure and sets @error.
5213 mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
5215 MONO_REQ_GC_UNSAFE_MODE;
5219 vtable = mono_class_vtable (domain, klass);
5220 g_assert (vtable); /* FIXME don't swallow the error */
5222 MonoObject *o = mono_object_new_specific_checked (vtable, error);
5227 * mono_object_new_pinned:
5229 * Same as mono_object_new, but the returned object will be pinned.
5230 * For SGEN, these objects will only be freed at appdomain unload.
5233 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
5235 MONO_REQ_GC_UNSAFE_MODE;
5239 mono_error_init (error);
5241 vtable = mono_class_vtable (domain, klass);
5242 g_assert (vtable); /* FIXME don't swallow the error */
5244 MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
5246 if (G_UNLIKELY (!o))
5247 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
5248 else if (G_UNLIKELY (vtable->klass->has_finalize))
5249 mono_object_register_finalizer (o);
5255 * mono_object_new_specific:
5256 * @vtable: the vtable of the object that we want to create
5258 * Returns: A newly created object with class and domain specified
5262 mono_object_new_specific (MonoVTable *vtable)
5265 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5266 mono_error_cleanup (&error);
5272 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
5274 MONO_REQ_GC_UNSAFE_MODE;
5278 mono_error_init (error);
5280 /* check for is_com_object for COM Interop */
5281 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
5284 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
5287 MonoClass *klass = mono_class_get_activation_services_class ();
5290 mono_class_init (klass);
5292 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
5294 mono_error_set_not_supported (error, "Linked away.");
5297 vtable->domain->create_proxy_for_type_method = im;
5300 pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
5301 if (!mono_error_ok (error))
5304 o = mono_runtime_invoke_checked (im, NULL, pa, error);
5305 if (!mono_error_ok (error))
5312 return mono_object_new_alloc_specific_checked (vtable, error);
5316 ves_icall_object_new_specific (MonoVTable *vtable)
5319 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5320 mono_error_set_pending_exception (&error);
5326 * mono_object_new_alloc_specific:
5327 * @vtable: virtual table for the object.
5329 * This function allocates a new `MonoObject` with the type derived
5330 * from the @vtable information. If the class of this object has a
5331 * finalizer, then the object will be tracked for finalization.
5333 * This method might raise an exception on errors. Use the
5334 * `mono_object_new_fast_checked` method if you want to manually raise
5337 * Returns: the allocated object.
5340 mono_object_new_alloc_specific (MonoVTable *vtable)
5343 MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
5344 mono_error_cleanup (&error);
5350 * mono_object_new_alloc_specific_checked:
5351 * @vtable: virtual table for the object.
5352 * @error: holds the error return value.
5354 * This function allocates a new `MonoObject` with the type derived
5355 * from the @vtable information. If the class of this object has a
5356 * finalizer, then the object will be tracked for finalization.
5358 * If there is not enough memory, the @error parameter will be set
5359 * and will contain a user-visible message with the amount of bytes
5360 * that were requested.
5362 * Returns: the allocated object, or NULL if there is not enough memory
5366 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
5368 MONO_REQ_GC_UNSAFE_MODE;
5372 mono_error_init (error);
5374 o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5376 if (G_UNLIKELY (!o))
5377 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5378 else if (G_UNLIKELY (vtable->klass->has_finalize))
5379 mono_object_register_finalizer (o);
5385 * mono_object_new_fast:
5386 * @vtable: virtual table for the object.
5388 * This function allocates a new `MonoObject` with the type derived
5389 * from the @vtable information. The returned object is not tracked
5390 * for finalization. If your object implements a finalizer, you should
5391 * use `mono_object_new_alloc_specific` instead.
5393 * This method might raise an exception on errors. Use the
5394 * `mono_object_new_fast_checked` method if you want to manually raise
5397 * Returns: the allocated object.
5400 mono_object_new_fast (MonoVTable *vtable)
5403 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5404 mono_error_cleanup (&error);
5410 * mono_object_new_fast_checked:
5411 * @vtable: virtual table for the object.
5412 * @error: holds the error return value.
5414 * This function allocates a new `MonoObject` with the type derived
5415 * from the @vtable information. The returned object is not tracked
5416 * for finalization. If your object implements a finalizer, you should
5417 * use `mono_object_new_alloc_specific_checked` instead.
5419 * If there is not enough memory, the @error parameter will be set
5420 * and will contain a user-visible message with the amount of bytes
5421 * that were requested.
5423 * Returns: the allocated object, or NULL if there is not enough memory
5427 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
5429 MONO_REQ_GC_UNSAFE_MODE;
5433 mono_error_init (error);
5435 o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5437 if (G_UNLIKELY (!o))
5438 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5444 ves_icall_object_new_fast (MonoVTable *vtable)
5447 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5448 mono_error_set_pending_exception (&error);
5454 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
5456 MONO_REQ_GC_UNSAFE_MODE;
5460 mono_error_init (error);
5462 o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
5464 if (G_UNLIKELY (!o))
5465 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5466 else if (G_UNLIKELY (vtable->klass->has_finalize))
5467 mono_object_register_finalizer (o);
5473 * mono_class_get_allocation_ftn:
5475 * @for_box: the object will be used for boxing
5476 * @pass_size_in_words:
5478 * Return the allocation function appropriate for the given class.
5482 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
5484 MONO_REQ_GC_NEUTRAL_MODE;
5486 *pass_size_in_words = FALSE;
5488 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass))
5489 return ves_icall_object_new_specific;
5491 if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
5493 return ves_icall_object_new_fast;
5496 * FIXME: This is actually slower than ves_icall_object_new_fast, because
5497 * of the overhead of parameter passing.
5500 *pass_size_in_words = TRUE;
5501 #ifdef GC_REDIRECT_TO_LOCAL
5502 return GC_local_gcj_fast_malloc;
5504 return GC_gcj_fast_malloc;
5509 return ves_icall_object_new_specific;
5513 * mono_object_new_from_token:
5514 * @image: Context where the type_token is hosted
5515 * @token: a token of the type that we want to create
5517 * Returns: A newly created object whose definition is
5518 * looked up using @token in the @image image
5521 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
5523 MONO_REQ_GC_UNSAFE_MODE;
5529 klass = mono_class_get_checked (image, token, &error);
5530 mono_error_assert_ok (&error);
5532 result = mono_object_new_checked (domain, klass, &error);
5534 mono_error_cleanup (&error);
5541 * mono_object_clone:
5542 * @obj: the object to clone
5544 * Returns: A newly created object who is a shallow copy of @obj
5547 mono_object_clone (MonoObject *obj)
5550 MonoObject *o = mono_object_clone_checked (obj, &error);
5551 mono_error_cleanup (&error);
5557 mono_object_clone_checked (MonoObject *obj, MonoError *error)
5559 MONO_REQ_GC_UNSAFE_MODE;
5564 mono_error_init (error);
5566 size = obj->vtable->klass->instance_size;
5568 if (obj->vtable->klass->rank)
5569 return (MonoObject*)mono_array_clone_checked ((MonoArray*)obj, error);
5571 o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
5573 if (G_UNLIKELY (!o)) {
5574 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5578 /* If the object doesn't contain references this will do a simple memmove. */
5579 mono_gc_wbarrier_object_copy (o, obj);
5581 if (obj->vtable->klass->has_finalize)
5582 mono_object_register_finalizer (o);
5587 * mono_array_full_copy:
5588 * @src: source array to copy
5589 * @dest: destination array
5591 * Copies the content of one array to another with exactly the same type and size.
5594 mono_array_full_copy (MonoArray *src, MonoArray *dest)
5596 MONO_REQ_GC_UNSAFE_MODE;
5599 MonoClass *klass = src->obj.vtable->klass;
5601 g_assert (klass == dest->obj.vtable->klass);
5603 size = mono_array_length (src);
5604 g_assert (size == mono_array_length (dest));
5605 size *= mono_array_element_size (klass);
5607 if (klass->element_class->valuetype) {
5608 if (klass->element_class->has_references)
5609 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
5611 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5613 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
5616 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5621 * mono_array_clone_in_domain:
5622 * @domain: the domain in which the array will be cloned into
5623 * @array: the array to clone
5624 * @error: set on error
5626 * This routine returns a copy of the array that is hosted on the
5627 * specified MonoDomain. On failure returns NULL and sets @error.
5630 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array, MonoError *error)
5632 MONO_REQ_GC_UNSAFE_MODE;
5637 MonoClass *klass = array->obj.vtable->klass;
5639 mono_error_init (error);
5641 if (array->bounds == NULL) {
5642 size = mono_array_length (array);
5643 o = mono_array_new_full_checked (domain, klass, &size, NULL, error);
5644 return_val_if_nok (error, NULL);
5646 size *= mono_array_element_size (klass);
5648 if (klass->element_class->valuetype) {
5649 if (klass->element_class->has_references)
5650 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5652 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5654 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5657 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5662 sizes = (uintptr_t *)alloca (klass->rank * sizeof(intptr_t) * 2);
5663 size = mono_array_element_size (klass);
5664 for (i = 0; i < klass->rank; ++i) {
5665 sizes [i] = array->bounds [i].length;
5666 size *= array->bounds [i].length;
5667 sizes [i + klass->rank] = array->bounds [i].lower_bound;
5669 o = mono_array_new_full_checked (domain, klass, sizes, (intptr_t*)sizes + klass->rank, error);
5670 return_val_if_nok (error, NULL);
5672 if (klass->element_class->valuetype) {
5673 if (klass->element_class->has_references)
5674 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5676 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5678 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5681 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5689 * @array: the array to clone
5691 * Returns: A newly created array who is a shallow copy of @array
5694 mono_array_clone (MonoArray *array)
5696 MONO_REQ_GC_UNSAFE_MODE;
5699 MonoArray *result = mono_array_clone_checked (array, &error);
5700 mono_error_cleanup (&error);
5705 * mono_array_clone_checked:
5706 * @array: the array to clone
5707 * @error: set on error
5709 * Returns: A newly created array who is a shallow copy of @array. On
5710 * failure returns NULL and sets @error.
5713 mono_array_clone_checked (MonoArray *array, MonoError *error)
5716 MONO_REQ_GC_UNSAFE_MODE;
5717 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array, error);
5720 /* helper macros to check for overflow when calculating the size of arrays */
5721 #ifdef MONO_BIG_ARRAYS
5722 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
5723 #define MYGUINT_MAX MYGUINT64_MAX
5724 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5725 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
5726 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5727 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
5728 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
5730 #define MYGUINT32_MAX 4294967295U
5731 #define MYGUINT_MAX MYGUINT32_MAX
5732 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5733 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
5734 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5735 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
5736 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
5740 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
5742 MONO_REQ_GC_NEUTRAL_MODE;
5746 byte_len = mono_array_element_size (klass);
5747 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
5750 if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
5752 byte_len += MONO_SIZEOF_MONO_ARRAY;
5760 * mono_array_new_full:
5761 * @domain: domain where the object is created
5762 * @array_class: array class
5763 * @lengths: lengths for each dimension in the array
5764 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
5766 * This routine creates a new array objects with the given dimensions,
5767 * lower bounds and type.
5770 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
5773 MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
5774 mono_error_cleanup (&error);
5780 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
5782 MONO_REQ_GC_UNSAFE_MODE;
5784 uintptr_t byte_len = 0, len, bounds_size;
5787 MonoArrayBounds *bounds;
5791 mono_error_init (error);
5793 if (!array_class->inited)
5794 mono_class_init (array_class);
5798 /* A single dimensional array with a 0 lower bound is the same as an szarray */
5799 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
5801 if (len > MONO_ARRAY_MAX_INDEX) {
5802 mono_error_set_generic_error (error, "System", "OverflowException", "");
5807 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
5809 for (i = 0; i < array_class->rank; ++i) {
5810 if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
5811 mono_error_set_generic_error (error, "System", "OverflowException", "");
5814 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5815 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5822 if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5823 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5829 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5830 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5833 byte_len = (byte_len + 3) & ~3;
5834 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5835 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5838 byte_len += bounds_size;
5841 * Following three lines almost taken from mono_object_new ():
5842 * they need to be kept in sync.
5844 vtable = mono_class_vtable_full (domain, array_class, error);
5845 return_val_if_nok (error, NULL);
5848 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5850 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5852 if (G_UNLIKELY (!o)) {
5853 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5857 array = (MonoArray*)o;
5859 bounds = array->bounds;
5862 for (i = 0; i < array_class->rank; ++i) {
5863 bounds [i].length = lengths [i];
5865 bounds [i].lower_bound = lower_bounds [i];
5874 * @domain: domain where the object is created
5875 * @eclass: element class
5876 * @n: number of array elements
5878 * This routine creates a new szarray with @n elements of type @eclass.
5881 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5883 MONO_REQ_GC_UNSAFE_MODE;
5886 MonoArray *result = mono_array_new_checked (domain, eclass, n, &error);
5887 mono_error_cleanup (&error);
5892 * mono_array_new_checked:
5893 * @domain: domain where the object is created
5894 * @eclass: element class
5895 * @n: number of array elements
5896 * @error: set on error
5898 * This routine creates a new szarray with @n elements of type @eclass.
5899 * On failure returns NULL and sets @error.
5902 mono_array_new_checked (MonoDomain *domain, MonoClass *eclass, uintptr_t n, MonoError *error)
5906 mono_error_init (error);
5908 ac = mono_array_class_get (eclass, 1);
5911 MonoVTable *vtable = mono_class_vtable_full (domain, ac, error);
5912 return_val_if_nok (error, NULL);
5914 return mono_array_new_specific_checked (vtable, n, error);
5918 ves_icall_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5921 MonoArray *arr = mono_array_new_checked (domain, eclass, n, &error);
5922 mono_error_set_pending_exception (&error);
5928 * mono_array_new_specific:
5929 * @vtable: a vtable in the appropriate domain for an initialized class
5930 * @n: number of array elements
5932 * This routine is a fast alternative to mono_array_new() for code which
5933 * can be sure about the domain it operates in.
5936 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5939 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5940 mono_error_cleanup (&error);
5946 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
5948 MONO_REQ_GC_UNSAFE_MODE;
5953 mono_error_init (error);
5955 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
5956 mono_error_set_generic_error (error, "System", "OverflowException", "");
5960 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
5961 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5964 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
5966 if (G_UNLIKELY (!o)) {
5967 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5971 return (MonoArray*)o;
5975 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
5978 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5979 mono_error_set_pending_exception (&error);
5985 * mono_string_empty_wrapper:
5987 * Returns: The same empty string instance as the managed string.Empty
5990 mono_string_empty_wrapper (void)
5992 MonoDomain *domain = mono_domain_get ();
5993 return mono_string_empty (domain);
5997 * mono_string_empty:
5999 * Returns: The same empty string instance as the managed string.Empty
6002 mono_string_empty (MonoDomain *domain)
6005 g_assert (domain->empty_string);
6006 return domain->empty_string;
6010 * mono_string_new_utf16:
6011 * @text: a pointer to an utf16 string
6012 * @len: the length of the string
6014 * Returns: A newly created string object which contains @text.
6017 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
6019 MONO_REQ_GC_UNSAFE_MODE;
6022 MonoString *res = NULL;
6023 res = mono_string_new_utf16_checked (domain, text, len, &error);
6024 mono_error_cleanup (&error);
6030 * mono_string_new_utf16_checked:
6031 * @text: a pointer to an utf16 string
6032 * @len: the length of the string
6033 * @error: written on error.
6035 * Returns: A newly created string object which contains @text.
6036 * On error, returns NULL and sets @error.
6039 mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
6041 MONO_REQ_GC_UNSAFE_MODE;
6045 mono_error_init (error);
6047 s = mono_string_new_size_checked (domain, len, error);
6049 memcpy (mono_string_chars (s), text, len * 2);
6055 * mono_string_new_utf32:
6056 * @text: a pointer to an utf32 string
6057 * @len: the length of the string
6058 * @error: set on failure.
6060 * Returns: A newly created string object which contains @text. On failure returns NULL and sets @error.
6063 mono_string_new_utf32_checked (MonoDomain *domain, const mono_unichar4 *text, gint32 len, MonoError *error)
6065 MONO_REQ_GC_UNSAFE_MODE;
6068 mono_unichar2 *utf16_output = NULL;
6069 gint32 utf16_len = 0;
6070 GError *gerror = NULL;
6071 glong items_written;
6073 mono_error_init (error);
6074 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
6077 g_error_free (gerror);
6079 while (utf16_output [utf16_len]) utf16_len++;
6081 s = mono_string_new_size_checked (domain, utf16_len, error);
6082 return_val_if_nok (error, NULL);
6084 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
6086 g_free (utf16_output);
6092 * mono_string_new_utf32:
6093 * @text: a pointer to an utf32 string
6094 * @len: the length of the string
6096 * Returns: A newly created string object which contains @text.
6099 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
6102 MonoString *result = mono_string_new_utf32_checked (domain, text, len, &error);
6103 mono_error_cleanup (&error);
6108 * mono_string_new_size:
6109 * @text: a pointer to an utf16 string
6110 * @len: the length of the string
6112 * Returns: A newly created string object of @len
6115 mono_string_new_size (MonoDomain *domain, gint32 len)
6118 MonoString *str = mono_string_new_size_checked (domain, len, &error);
6119 mono_error_cleanup (&error);
6125 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
6127 MONO_REQ_GC_UNSAFE_MODE;
6133 mono_error_init (error);
6135 /* check for overflow */
6136 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
6137 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
6141 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
6142 g_assert (size > 0);
6144 vtable = mono_class_vtable (domain, mono_defaults.string_class);
6147 s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
6149 if (G_UNLIKELY (!s)) {
6150 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", size);
6158 * mono_string_new_len:
6159 * @text: a pointer to an utf8 string
6160 * @length: number of bytes in @text to consider
6162 * Returns: A newly created string object which contains @text.
6165 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
6167 MONO_REQ_GC_UNSAFE_MODE;
6170 MonoString *result = mono_string_new_len_checked (domain, text, length, &error);
6171 mono_error_cleanup (&error);
6176 * mono_string_new_len_checked:
6177 * @text: a pointer to an utf8 string
6178 * @length: number of bytes in @text to consider
6179 * @error: set on error
6181 * Returns: A newly created string object which contains @text. On
6182 * failure returns NULL and sets @error.
6185 mono_string_new_len_checked (MonoDomain *domain, const char *text, guint length, MonoError *error)
6187 MONO_REQ_GC_UNSAFE_MODE;
6189 mono_error_init (error);
6191 GError *eg_error = NULL;
6192 MonoString *o = NULL;
6194 glong items_written;
6196 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
6199 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6201 g_error_free (eg_error);
6210 * @text: a pointer to an utf8 string
6212 * Returns: A newly created string object which contains @text.
6214 * This function asserts if it cannot allocate a new string.
6216 * @deprecated Use mono_string_new_checked in new code.
6219 mono_string_new (MonoDomain *domain, const char *text)
6222 MonoString *res = NULL;
6223 res = mono_string_new_checked (domain, text, &error);
6224 mono_error_assert_ok (&error);
6229 * mono_string_new_checked:
6230 * @text: a pointer to an utf8 string
6231 * @merror: set on error
6233 * Returns: A newly created string object which contains @text.
6234 * On error returns NULL and sets @merror.
6237 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
6239 MONO_REQ_GC_UNSAFE_MODE;
6241 GError *eg_error = NULL;
6242 MonoString *o = NULL;
6244 glong items_written;
6247 mono_error_init (error);
6251 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &eg_error);
6254 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6256 g_error_free (eg_error);
6260 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
6265 MonoString *o = NULL;
6267 if (!g_utf8_validate (text, -1, &end)) {
6268 mono_error_set_argument (error, "text", "Not a valid utf8 string");
6272 len = g_utf8_strlen (text, -1);
6273 o = mono_string_new_size_checked (domain, len, error);
6276 str = mono_string_chars (o);
6278 while (text < end) {
6279 *str++ = g_utf8_get_char (text);
6280 text = g_utf8_next_char (text);
6289 * mono_string_new_wrapper:
6290 * @text: pointer to utf8 characters.
6292 * Helper function to create a string object from @text in the current domain.
6295 mono_string_new_wrapper (const char *text)
6297 MONO_REQ_GC_UNSAFE_MODE;
6299 MonoDomain *domain = mono_domain_get ();
6302 return mono_string_new (domain, text);
6309 * @class: the class of the value
6310 * @value: a pointer to the unboxed data
6312 * Returns: A newly created object which contains @value.
6315 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
6318 MonoObject *result = mono_value_box_checked (domain, klass, value, &error);
6319 mono_error_cleanup (&error);
6324 * mono_value_box_checked:
6325 * @domain: the domain of the new object
6326 * @class: the class of the value
6327 * @value: a pointer to the unboxed data
6328 * @error: set on error
6330 * Returns: A newly created object which contains @value. On failure
6331 * returns NULL and sets @error.
6334 mono_value_box_checked (MonoDomain *domain, MonoClass *klass, gpointer value, MonoError *error)
6336 MONO_REQ_GC_UNSAFE_MODE;
6341 mono_error_init (error);
6343 g_assert (klass->valuetype);
6344 if (mono_class_is_nullable (klass))
6345 return mono_nullable_box ((guint8 *)value, klass, error);
6347 vtable = mono_class_vtable (domain, klass);
6350 size = mono_class_instance_size (klass);
6351 res = mono_object_new_alloc_specific_checked (vtable, error);
6352 return_val_if_nok (error, NULL);
6354 size = size - sizeof (MonoObject);
6357 g_assert (size == mono_class_value_size (klass, NULL));
6358 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
6360 #if NO_UNALIGNED_ACCESS
6361 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6365 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
6368 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
6371 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
6374 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
6377 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6381 if (klass->has_finalize) {
6382 mono_object_register_finalizer (res);
6383 return_val_if_nok (error, NULL);
6390 * @dest: destination pointer
6391 * @src: source pointer
6392 * @klass: a valuetype class
6394 * Copy a valuetype from @src to @dest. This function must be used
6395 * when @klass contains references fields.
6398 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
6400 MONO_REQ_GC_UNSAFE_MODE;
6402 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
6406 * mono_value_copy_array:
6407 * @dest: destination array
6408 * @dest_idx: index in the @dest array
6409 * @src: source pointer
6410 * @count: number of items
6412 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
6413 * This function must be used when @klass contains references fields.
6414 * Overlap is handled.
6417 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
6419 MONO_REQ_GC_UNSAFE_MODE;
6421 int size = mono_array_element_size (dest->obj.vtable->klass);
6422 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
6423 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
6424 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
6428 * mono_object_get_domain:
6429 * @obj: object to query
6431 * Returns: the MonoDomain where the object is hosted
6434 mono_object_get_domain (MonoObject *obj)
6436 MONO_REQ_GC_UNSAFE_MODE;
6438 return mono_object_domain (obj);
6442 * mono_object_get_class:
6443 * @obj: object to query
6445 * Use this function to obtain the `MonoClass*` for a given `MonoObject`.
6447 * Returns: the MonoClass of the object.
6450 mono_object_get_class (MonoObject *obj)
6452 MONO_REQ_GC_UNSAFE_MODE;
6454 return mono_object_class (obj);
6457 * mono_object_get_size:
6458 * @o: object to query
6460 * Returns: the size, in bytes, of @o
6463 mono_object_get_size (MonoObject* o)
6465 MONO_REQ_GC_UNSAFE_MODE;
6467 MonoClass* klass = mono_object_class (o);
6468 if (klass == mono_defaults.string_class) {
6469 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
6470 } else if (o->vtable->rank) {
6471 MonoArray *array = (MonoArray*)o;
6472 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
6473 if (array->bounds) {
6476 size += sizeof (MonoArrayBounds) * o->vtable->rank;
6480 return mono_class_instance_size (klass);
6485 * mono_object_unbox:
6486 * @obj: object to unbox
6488 * Returns: a pointer to the start of the valuetype boxed in this
6491 * This method will assert if the object passed is not a valuetype.
6494 mono_object_unbox (MonoObject *obj)
6496 MONO_REQ_GC_UNSAFE_MODE;
6498 /* add assert for valuetypes? */
6499 g_assert (obj->vtable->klass->valuetype);
6500 return ((char*)obj) + sizeof (MonoObject);
6504 * mono_object_isinst:
6506 * @klass: a pointer to a class
6508 * Returns: @obj if @obj is derived from @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:
6527 * @klass: a pointer to a class
6528 * @error: set on error
6530 * Returns: @obj if @obj is derived from @klass or NULL if it isn't.
6531 * On failure returns NULL and sets @error.
6534 mono_object_isinst_checked (MonoObject *obj_raw, MonoClass *klass, MonoError *error)
6536 MONO_REQ_GC_UNSAFE_MODE;
6538 HANDLE_FUNCTION_ENTER ();
6539 mono_error_init (error);
6540 MONO_HANDLE_DCL (MonoObject, obj);
6541 MonoObjectHandle result = mono_object_handle_isinst (obj, klass, error);
6542 HANDLE_FUNCTION_RETURN_OBJ (result);
6546 * mono_object_handle_isinst:
6548 * @klass: a pointer to a class
6549 * @error: set on error
6551 * Returns: @obj if @obj is derived from @klass or NULL if it isn't.
6552 * On failure returns NULL and sets @error.
6555 mono_object_handle_isinst (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
6557 mono_error_init (error);
6560 mono_class_init (klass);
6562 if (mono_class_is_marshalbyref (klass) || mono_class_is_interface (klass)) {
6563 return mono_object_handle_isinst_mbyref (obj, klass, error);
6566 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6568 if (!MONO_HANDLE_IS_NULL (obj) && mono_class_is_assignable_from (klass, mono_handle_class (obj)))
6569 MONO_HANDLE_ASSIGN (result, obj);
6574 mono_object_isinst_mbyref (MonoObject *obj_raw, MonoClass *klass)
6576 MONO_REQ_GC_UNSAFE_MODE;
6578 HANDLE_FUNCTION_ENTER ();
6580 MONO_HANDLE_DCL (MonoObject, obj);
6581 MonoObjectHandle result = mono_object_handle_isinst_mbyref (obj, klass, &error);
6582 mono_error_cleanup (&error); /* FIXME better API that doesn't swallow the error */
6583 HANDLE_FUNCTION_RETURN_OBJ (result);
6587 mono_object_handle_isinst_mbyref (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
6589 mono_error_init (error);
6591 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6593 if (MONO_HANDLE_IS_NULL (obj))
6596 MonoVTable *vt = MONO_HANDLE_GETVAL (obj, vtable);
6598 if (mono_class_is_interface (klass)) {
6599 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
6600 MONO_HANDLE_ASSIGN (result, obj);
6604 /* casting an array one of the invariant interfaces that must act as such */
6605 if (klass->is_array_special_interface) {
6606 if (mono_class_is_assignable_from (klass, vt->klass)) {
6607 MONO_HANDLE_ASSIGN (result, obj);
6612 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
6613 else if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, mono_handle_class (obj))) {
6614 MONO_HANDLE_ASSIGN (result, obj);
6618 MonoClass *oklass = vt->klass;
6619 if (mono_class_is_transparent_proxy (oklass)){
6620 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), remote_class);
6621 oklass = remote_class->proxy_class;
6624 mono_class_setup_supertypes (klass);
6625 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass)) {
6626 MONO_HANDLE_ASSIGN (result, obj);
6630 #ifndef DISABLE_REMOTING
6631 if (mono_class_is_transparent_proxy (vt->klass))
6633 MonoBoolean custom_type_info = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), custom_type_info);
6634 if (!custom_type_info)
6636 MonoDomain *domain = mono_domain_get ();
6637 MonoObjectHandle rp = MONO_HANDLE_NEW (MonoObject, NULL);
6638 MONO_HANDLE_GET (rp, MONO_HANDLE_CAST (MonoTransparentProxy, obj), rp);
6639 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
6640 MonoMethod *im = NULL;
6643 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
6645 mono_error_set_not_supported (error, "Linked away.");
6648 im = mono_object_handle_get_virtual_method (rp, im, error);
6653 MonoReflectionTypeHandle reftype = mono_type_get_object_handle (domain, &klass->byval_arg, error);
6657 pa [0] = MONO_HANDLE_RAW (reftype);
6658 pa [1] = MONO_HANDLE_RAW (obj);
6659 MonoObject *res = mono_runtime_invoke_checked (im, rp, pa, error);
6663 if (*(MonoBoolean *) mono_object_unbox(res)) {
6664 /* Update the vtable of the remote type, so it can safely cast to this new type */
6665 mono_upgrade_remote_class (domain, obj, klass, error);
6668 MONO_HANDLE_ASSIGN (result, obj);
6671 #endif /* DISABLE_REMOTING */
6677 * mono_object_castclass_mbyref:
6679 * @klass: a pointer to a class
6681 * Returns: @obj if @obj is derived from @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;
6721 mono_error_init (error);
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;
6748 mono_error_init (error);
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 * @o: String to probe
6799 * Returns whether the string has been interned.
6802 mono_string_is_interned (MonoString *o)
6805 MonoString *result = mono_string_is_interned_lookup (o, FALSE, &error);
6806 /* This function does not fail. */
6807 mono_error_assert_ok (&error);
6812 * mono_string_intern:
6813 * @o: String to intern
6815 * Interns the string passed.
6816 * Returns: The interned string.
6819 mono_string_intern (MonoString *str)
6822 MonoString *result = mono_string_intern_checked (str, &error);
6823 mono_error_assert_ok (&error);
6828 * mono_string_intern_checked:
6829 * @o: String to intern
6830 * @error: set on error.
6832 * Interns the string passed.
6833 * Returns: The interned string. On failure returns NULL and sets @error
6836 mono_string_intern_checked (MonoString *str, MonoError *error)
6838 MONO_REQ_GC_UNSAFE_MODE;
6840 mono_error_init (error);
6842 return mono_string_is_interned_lookup (str, TRUE, error);
6847 * @domain: the domain where the string will be used.
6848 * @image: a metadata context
6849 * @idx: index into the user string table.
6851 * Implementation for the ldstr opcode.
6852 * Returns: a loaded string from the @image/@idx combination.
6855 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
6858 MonoString *result = mono_ldstr_checked (domain, image, idx, &error);
6859 mono_error_cleanup (&error);
6864 * mono_ldstr_checked:
6865 * @domain: the domain where the string will be used.
6866 * @image: a metadata context
6867 * @idx: index into the user string table.
6868 * @error: set on error.
6870 * Implementation for the ldstr opcode.
6871 * Returns: a loaded string from the @image/@idx combination.
6872 * On failure returns NULL and sets @error.
6875 mono_ldstr_checked (MonoDomain *domain, MonoImage *image, guint32 idx, MonoError *error)
6877 MONO_REQ_GC_UNSAFE_MODE;
6878 mono_error_init (error);
6880 if (image->dynamic) {
6881 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL, error);
6884 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6885 return NULL; /*FIXME we should probably be raising an exception here*/
6886 MonoString *str = mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx), error);
6892 * mono_ldstr_metadata_sig
6893 * @domain: the domain for the string
6894 * @sig: the signature of a metadata string
6895 * @error: set on error
6897 * Returns: a MonoString for a string stored in the metadata. On
6898 * failure returns NULL and sets @error.
6901 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error)
6903 MONO_REQ_GC_UNSAFE_MODE;
6905 mono_error_init (error);
6906 const char *str = sig;
6907 MonoString *o, *interned;
6910 len2 = mono_metadata_decode_blob_size (str, &str);
6913 o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, error);
6914 return_val_if_nok (error, NULL);
6915 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
6918 guint16 *p2 = (guint16*)mono_string_chars (o);
6919 for (i = 0; i < len2; ++i) {
6920 *p2 = GUINT16_FROM_LE (*p2);
6926 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6929 return interned; /* o will get garbage collected */
6931 o = mono_string_get_pinned (o, error);
6934 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6936 mono_g_hash_table_insert (domain->ldstr_table, o, o);
6948 * Same as mono_ldstr, but return a NULL terminated utf8 string instead
6952 mono_ldstr_utf8 (MonoImage *image, guint32 idx, MonoError *error)
6958 GError *gerror = NULL;
6960 mono_error_init (error);
6962 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6963 return NULL; /*FIXME we should probably be raising an exception here*/
6964 str = mono_metadata_user_string (image, idx);
6966 len2 = mono_metadata_decode_blob_size (str, &str);
6969 as = g_utf16_to_utf8 ((guint16*)str, len2, NULL, &written, &gerror);
6971 mono_error_set_argument (error, "string", "%s", gerror->message);
6972 g_error_free (gerror);
6975 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6976 if (len2 > written) {
6977 /* allocate the total length and copy the part of the string that has been converted */
6978 char *as2 = (char *)g_malloc0 (len2);
6979 memcpy (as2, as, written);
6988 * mono_string_to_utf8:
6989 * @s: a System.String
6991 * Returns the UTF8 representation for @s.
6992 * The resulting buffer needs to be freed with mono_free().
6994 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
6997 mono_string_to_utf8 (MonoString *s)
6999 MONO_REQ_GC_UNSAFE_MODE;
7002 char *result = mono_string_to_utf8_checked (s, &error);
7004 if (!is_ok (&error)) {
7005 mono_error_cleanup (&error);
7012 * mono_string_to_utf8_checked:
7013 * @s: a System.String
7014 * @error: a MonoError.
7016 * Converts a MonoString to its UTF8 representation. May fail; check
7017 * @error to determine whether the conversion was successful.
7018 * The resulting buffer should be freed with mono_free().
7021 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
7023 MONO_REQ_GC_UNSAFE_MODE;
7027 GError *gerror = NULL;
7029 mono_error_init (error);
7035 return g_strdup ("");
7037 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
7039 mono_error_set_argument (error, "string", "%s", gerror->message);
7040 g_error_free (gerror);
7043 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
7044 if (s->length > written) {
7045 /* allocate the total length and copy the part of the string that has been converted */
7046 char *as2 = (char *)g_malloc0 (s->length);
7047 memcpy (as2, as, written);
7056 mono_string_handle_to_utf8 (MonoStringHandle s, MonoError *error)
7058 return mono_string_to_utf8_checked (MONO_HANDLE_RAW (s), error);
7062 * mono_string_to_utf8_ignore:
7065 * Converts a MonoString to its UTF8 representation. Will ignore
7066 * invalid surrogate pairs.
7067 * The resulting buffer should be freed with mono_free().
7071 mono_string_to_utf8_ignore (MonoString *s)
7073 MONO_REQ_GC_UNSAFE_MODE;
7082 return g_strdup ("");
7084 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
7086 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
7087 if (s->length > written) {
7088 /* allocate the total length and copy the part of the string that has been converted */
7089 char *as2 = (char *)g_malloc0 (s->length);
7090 memcpy (as2, as, written);
7099 * mono_string_to_utf8_image_ignore:
7100 * @s: a System.String
7102 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
7105 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
7107 MONO_REQ_GC_UNSAFE_MODE;
7109 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
7113 * mono_string_to_utf8_mp_ignore:
7114 * @s: a System.String
7116 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
7119 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
7121 MONO_REQ_GC_UNSAFE_MODE;
7123 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
7128 * mono_string_to_utf16:
7131 * Return an null-terminated array of the utf-16 chars
7132 * contained in @s. The result must be freed with g_free().
7133 * This is a temporary helper until our string implementation
7134 * is reworked to always include the null terminating char.
7137 mono_string_to_utf16 (MonoString *s)
7139 MONO_REQ_GC_UNSAFE_MODE;
7146 as = (char *)g_malloc ((s->length * 2) + 2);
7147 as [(s->length * 2)] = '\0';
7148 as [(s->length * 2) + 1] = '\0';
7151 return (gunichar2 *)(as);
7154 memcpy (as, mono_string_chars(s), s->length * 2);
7155 return (gunichar2 *)(as);
7159 * mono_string_to_utf32:
7162 * Return an null-terminated array of the UTF-32 (UCS-4) chars
7163 * contained in @s. The result must be freed with g_free().
7166 mono_string_to_utf32 (MonoString *s)
7168 MONO_REQ_GC_UNSAFE_MODE;
7170 mono_unichar4 *utf32_output = NULL;
7171 GError *error = NULL;
7172 glong items_written;
7177 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
7180 g_error_free (error);
7182 return utf32_output;
7186 * mono_string_from_utf16:
7187 * @data: the UTF16 string (LPWSTR) to convert
7189 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
7191 * Returns: a MonoString.
7194 mono_string_from_utf16 (gunichar2 *data)
7197 MonoString *result = mono_string_from_utf16_checked (data, &error);
7198 mono_error_cleanup (&error);
7203 * mono_string_from_utf16_checked:
7204 * @data: the UTF16 string (LPWSTR) to convert
7205 * @error: set on error
7207 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
7209 * Returns: a MonoString. On failure sets @error and returns NULL.
7212 mono_string_from_utf16_checked (gunichar2 *data, MonoError *error)
7215 MONO_REQ_GC_UNSAFE_MODE;
7217 mono_error_init (error);
7218 MonoDomain *domain = mono_domain_get ();
7224 while (data [len]) len++;
7226 return mono_string_new_utf16_checked (domain, data, len, error);
7230 * mono_string_from_utf32:
7231 * @data: the UTF32 string (LPWSTR) to convert
7233 * Converts a UTF32 (UCS-4)to a MonoString.
7235 * Returns: a MonoString.
7238 mono_string_from_utf32 (mono_unichar4 *data)
7241 MonoString *result = mono_string_from_utf32_checked (data, &error);
7242 mono_error_cleanup (&error);
7247 * mono_string_from_utf32_checked:
7248 * @data: the UTF32 string (LPWSTR) to convert
7249 * @error: set on error
7251 * Converts a UTF32 (UCS-4)to a MonoString.
7253 * Returns: a MonoString. On failure returns NULL and sets @error.
7256 mono_string_from_utf32_checked (mono_unichar4 *data, MonoError *error)
7258 MONO_REQ_GC_UNSAFE_MODE;
7260 mono_error_init (error);
7261 MonoString* result = NULL;
7262 mono_unichar2 *utf16_output = NULL;
7263 GError *gerror = NULL;
7264 glong items_written;
7270 while (data [len]) len++;
7272 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &gerror);
7275 g_error_free (gerror);
7277 result = mono_string_from_utf16_checked (utf16_output, error);
7278 g_free (utf16_output);
7283 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
7285 MONO_REQ_GC_UNSAFE_MODE;
7292 r = mono_string_to_utf8_ignore (s);
7294 r = mono_string_to_utf8_checked (s, error);
7295 if (!mono_error_ok (error))
7302 len = strlen (r) + 1;
7304 mp_s = (char *)mono_mempool_alloc (mp, len);
7306 mp_s = (char *)mono_image_alloc (image, len);
7308 memcpy (mp_s, r, len);
7316 * mono_string_to_utf8_image:
7317 * @s: a System.String
7319 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
7322 mono_string_to_utf8_image (MonoImage *image, MonoStringHandle s, MonoError *error)
7324 MONO_REQ_GC_UNSAFE_MODE;
7326 return mono_string_to_utf8_internal (NULL, image, MONO_HANDLE_RAW (s), FALSE, error); /* FIXME pin the string */
7330 * mono_string_to_utf8_mp:
7331 * @s: a System.String
7333 * Same as mono_string_to_utf8, but allocate the string from a mempool.
7336 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
7338 MONO_REQ_GC_UNSAFE_MODE;
7340 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
7344 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
7347 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
7349 eh_callbacks = *cbs;
7352 MonoRuntimeExceptionHandlingCallbacks *
7353 mono_get_eh_callbacks (void)
7355 return &eh_callbacks;
7359 * mono_raise_exception:
7360 * @ex: exception object
7362 * Signal the runtime that the exception @ex has been raised in unmanaged code.
7365 mono_raise_exception (MonoException *ex)
7367 MONO_REQ_GC_UNSAFE_MODE;
7370 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
7371 * that will cause gcc to omit the function epilog, causing problems when
7372 * the JIT tries to walk the stack, since the return address on the stack
7373 * will point into the next function in the executable, not this one.
7375 eh_callbacks.mono_raise_exception (ex);
7379 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
7381 MONO_REQ_GC_UNSAFE_MODE;
7383 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
7387 * mono_wait_handle_new:
7388 * @domain: Domain where the object will be created
7389 * @handle: Handle for the wait handle
7390 * @error: set on error.
7392 * Returns: A new MonoWaitHandle created in the given domain for the
7393 * given handle. On failure returns NULL and sets @rror.
7396 mono_wait_handle_new (MonoDomain *domain, HANDLE handle, MonoError *error)
7398 MONO_REQ_GC_UNSAFE_MODE;
7400 MonoWaitHandle *res;
7401 gpointer params [1];
7402 static MonoMethod *handle_set;
7404 mono_error_init (error);
7405 res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, error);
7406 return_val_if_nok (error, NULL);
7408 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
7410 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
7412 params [0] = &handle;
7414 mono_runtime_invoke_checked (handle_set, res, params, error);
7419 mono_wait_handle_get_handle (MonoWaitHandle *handle)
7421 MONO_REQ_GC_UNSAFE_MODE;
7423 static MonoClassField *f_safe_handle = NULL;
7426 if (!f_safe_handle) {
7427 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safeWaitHandle");
7428 g_assert (f_safe_handle);
7431 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
7437 mono_runtime_capture_context (MonoDomain *domain, MonoError *error)
7439 MONO_REQ_GC_UNSAFE_MODE;
7441 RuntimeInvokeFunction runtime_invoke;
7443 mono_error_init (error);
7445 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
7446 MonoMethod *method = mono_get_context_capture_method ();
7447 MonoMethod *wrapper;
7450 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
7451 domain->capture_context_runtime_invoke = mono_compile_method_checked (wrapper, error);
7452 return_val_if_nok (error, NULL);
7453 domain->capture_context_method = mono_compile_method_checked (method, error);
7454 return_val_if_nok (error, NULL);
7457 runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
7459 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
7462 * mono_async_result_new:
7463 * @domain:domain where the object will be created.
7464 * @handle: wait handle.
7465 * @state: state to pass to AsyncResult
7466 * @data: C closure data.
7467 * @error: set on error.
7469 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
7470 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
7471 * On failure returns NULL and sets @error.
7475 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data, MonoError *error)
7477 MONO_REQ_GC_UNSAFE_MODE;
7479 mono_error_init (error);
7480 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, error);
7481 return_val_if_nok (error, NULL);
7482 MonoObject *context = mono_runtime_capture_context (domain, error);
7483 return_val_if_nok (error, NULL);
7484 /* we must capture the execution context from the original thread */
7486 MONO_OBJECT_SETREF (res, execution_context, context);
7487 /* note: result may be null if the flow is suppressed */
7490 res->data = (void **)data;
7491 MONO_OBJECT_SETREF (res, object_data, object_data);
7492 MONO_OBJECT_SETREF (res, async_state, state);
7493 MonoWaitHandle *wait_handle = mono_wait_handle_new (domain, handle, error);
7494 return_val_if_nok (error, NULL);
7496 MONO_OBJECT_SETREF (res, handle, (MonoObject *) wait_handle);
7498 res->sync_completed = FALSE;
7499 res->completed = FALSE;
7505 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
7507 MONO_REQ_GC_UNSAFE_MODE;
7514 g_assert (ares->async_delegate);
7516 ac = (MonoAsyncCall*) ares->object_data;
7518 res = mono_runtime_delegate_invoke_checked (ares->async_delegate, (void**) &ares->async_state, &error);
7519 if (mono_error_set_pending_exception (&error))
7522 gpointer wait_event = NULL;
7524 ac->msg->exc = NULL;
7526 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args, &error);
7528 /* The exit side of the invoke must not be aborted as it would leave the runtime in an undefined state */
7529 mono_threads_begin_abort_protected_block ();
7531 if (!ac->msg->exc) {
7532 MonoException *ex = mono_error_convert_to_exception (&error);
7533 ac->msg->exc = (MonoObject *)ex;
7535 mono_error_cleanup (&error);
7538 MONO_OBJECT_SETREF (ac, res, res);
7540 mono_monitor_enter ((MonoObject*) ares);
7541 ares->completed = 1;
7543 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
7544 mono_monitor_exit ((MonoObject*) ares);
7546 if (wait_event != NULL)
7547 mono_w32event_set (wait_event);
7549 mono_error_init (&error); //the else branch would leave it in an undefined state
7551 mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
7553 mono_threads_end_abort_protected_block ();
7555 if (mono_error_set_pending_exception (&error))
7563 mono_message_init (MonoDomain *domain,
7564 MonoMethodMessage *this_obj,
7565 MonoReflectionMethod *method,
7566 MonoArray *out_args,
7569 MONO_REQ_GC_UNSAFE_MODE;
7571 static MonoMethod *init_message_method = NULL;
7573 if (!init_message_method) {
7574 init_message_method = mono_class_get_method_from_name (mono_defaults.mono_method_message_class, "InitMessage", 2);
7575 g_assert (init_message_method != NULL);
7578 mono_error_init (error);
7579 /* FIXME set domain instead? */
7580 g_assert (domain == mono_domain_get ());
7587 mono_runtime_invoke_checked (init_message_method, this_obj, args, error);
7588 return is_ok (error);
7591 #ifndef DISABLE_REMOTING
7593 * mono_remoting_invoke:
7594 * @real_proxy: pointer to a RealProxy object
7595 * @msg: The MonoMethodMessage to execute
7596 * @exc: used to store exceptions
7597 * @out_args: used to store output arguments
7599 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
7600 * IMessage interface and it is not trivial to extract results from there. So
7601 * we call an helper method PrivateInvoke instead of calling
7602 * RealProxy::Invoke() directly.
7604 * Returns: the result object.
7607 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, MonoObject **exc, MonoArray **out_args, MonoError *error)
7609 MONO_REQ_GC_UNSAFE_MODE;
7612 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
7617 mono_error_init (error);
7619 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
7622 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
7624 mono_error_set_not_supported (error, "Linked away.");
7627 real_proxy->vtable->domain->private_invoke_method = im;
7630 pa [0] = real_proxy;
7635 o = mono_runtime_try_invoke (im, NULL, pa, exc, error);
7636 return_val_if_nok (error, NULL);
7643 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
7644 MonoObject **exc, MonoArray **out_args, MonoError *error)
7646 MONO_REQ_GC_UNSAFE_MODE;
7648 static MonoClass *object_array_klass;
7649 mono_error_init (error);
7653 MonoMethodSignature *sig;
7655 int i, j, outarg_count = 0;
7657 #ifndef DISABLE_REMOTING
7658 if (target && mono_object_is_transparent_proxy (target)) {
7659 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
7660 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7661 target = tp->rp->unwrapped_server;
7663 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args, error);
7668 domain = mono_domain_get ();
7669 method = msg->method->method;
7670 sig = mono_method_signature (method);
7672 for (i = 0; i < sig->param_count; i++) {
7673 if (sig->params [i]->byref)
7677 if (!object_array_klass) {
7680 klass = mono_array_class_get (mono_defaults.object_class, 1);
7683 mono_memory_barrier ();
7684 object_array_klass = klass;
7687 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, error);
7688 return_val_if_nok (error, NULL);
7690 mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
7693 MonoObject *ret = mono_runtime_try_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc, error);
7694 return_val_if_nok (error, NULL);
7696 for (i = 0, j = 0; i < sig->param_count; i++) {
7697 if (sig->params [i]->byref) {
7699 arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
7700 mono_array_setref (*out_args, j, arg);
7709 * prepare_to_string_method:
7711 * @target: Set to @obj or unboxed value if a valuetype
7713 * Returns: the ToString override for @obj. If @obj is a valuetype, @target is unboxed otherwise it's @obj.
7716 prepare_to_string_method (MonoObject *obj, void **target)
7718 MONO_REQ_GC_UNSAFE_MODE;
7720 static MonoMethod *to_string = NULL;
7728 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
7730 method = mono_object_get_virtual_method (obj, to_string);
7732 // Unbox value type if needed
7733 if (mono_class_is_valuetype (mono_method_get_class (method))) {
7734 *target = mono_object_unbox (obj);
7740 * mono_object_to_string:
7742 * @exc: Any exception thrown by ToString (). May be NULL.
7744 * Returns: the result of calling ToString () on an object.
7747 mono_object_to_string (MonoObject *obj, MonoObject **exc)
7750 MonoString *s = NULL;
7752 MonoMethod *method = prepare_to_string_method (obj, &target);
7754 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
7755 if (*exc == NULL && !mono_error_ok (&error))
7756 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
7758 mono_error_cleanup (&error);
7760 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
7761 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
7768 * mono_object_to_string_checked:
7770 * @error: Set on error.
7772 * Returns: the result of calling ToString () on an object. If the
7773 * method cannot be invoked or if it raises an exception, sets @error
7777 mono_object_to_string_checked (MonoObject *obj, MonoError *error)
7779 mono_error_init (error);
7781 MonoMethod *method = prepare_to_string_method (obj, &target);
7782 return (MonoString*) mono_runtime_invoke_checked (method, target, NULL, error);
7786 * mono_object_try_to_string:
7788 * @exc: Any exception thrown by ToString (). Must not be NULL.
7789 * @error: Set if method cannot be invoked.
7791 * Returns: the result of calling ToString () on an object. If the
7792 * method cannot be invoked sets @error, if it raises an exception sets @exc,
7796 mono_object_try_to_string (MonoObject *obj, MonoObject **exc, MonoError *error)
7799 mono_error_init (error);
7801 MonoMethod *method = prepare_to_string_method (obj, &target);
7802 return (MonoString*) mono_runtime_try_invoke (method, target, NULL, exc, error);
7808 get_native_backtrace (MonoException *exc_raw)
7810 HANDLE_FUNCTION_ENTER ();
7811 MONO_HANDLE_DCL(MonoException, exc);
7812 char * trace = mono_exception_handle_get_native_backtrace (exc);
7813 HANDLE_FUNCTION_RETURN_VAL (trace);
7817 * mono_print_unhandled_exception:
7818 * @exc: The exception
7820 * Prints the unhandled exception.
7823 mono_print_unhandled_exception (MonoObject *exc)
7825 MONO_REQ_GC_UNSAFE_MODE;
7828 char *message = (char*)"";
7829 gboolean free_message = FALSE;
7832 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
7833 message = g_strdup ("OutOfMemoryException");
7834 free_message = TRUE;
7835 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
7836 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
7837 free_message = TRUE;
7840 if (((MonoException*)exc)->native_trace_ips) {
7841 message = get_native_backtrace ((MonoException*)exc);
7842 free_message = TRUE;
7844 MonoObject *other_exc = NULL;
7845 str = mono_object_try_to_string (exc, &other_exc, &error);
7846 if (other_exc == NULL && !is_ok (&error))
7847 other_exc = (MonoObject*)mono_error_convert_to_exception (&error);
7849 mono_error_cleanup (&error);
7851 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
7852 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
7854 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
7855 original_backtrace, nested_backtrace);
7857 g_free (original_backtrace);
7858 g_free (nested_backtrace);
7859 free_message = TRUE;
7861 message = mono_string_to_utf8_checked (str, &error);
7862 if (!mono_error_ok (&error)) {
7863 mono_error_cleanup (&error);
7864 message = (char *) "";
7866 free_message = TRUE;
7873 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
7874 * exc->vtable->klass->name, message);
7876 g_printerr ("\nUnhandled Exception:\n%s\n", message);
7883 * mono_delegate_ctor_with_method:
7884 * @this: pointer to an uninitialized delegate object
7885 * @target: target object
7886 * @addr: pointer to native code
7888 * @error: set on error.
7890 * Initialize a delegate and sets a specific method, not the one
7891 * associated with addr. This is useful when sharing generic code.
7892 * In that case addr will most probably not be associated with the
7893 * correct instantiation of the method.
7894 * On failure returns FALSE and sets @error.
7897 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method, MonoError *error)
7899 MONO_REQ_GC_UNSAFE_MODE;
7901 mono_error_init (error);
7902 MonoDelegate *delegate = (MonoDelegate *)this_obj;
7904 g_assert (this_obj);
7907 g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
7910 delegate->method = method;
7912 mono_stats.delegate_creations++;
7914 #ifndef DISABLE_REMOTING
7915 if (target && mono_object_is_transparent_proxy (target)) {
7917 method = mono_marshal_get_remoting_invoke (method);
7918 delegate->method_ptr = mono_compile_method_checked (method, error);
7919 return_val_if_nok (error, FALSE);
7920 MONO_OBJECT_SETREF (delegate, target, target);
7924 delegate->method_ptr = addr;
7925 MONO_OBJECT_SETREF (delegate, target, target);
7928 delegate->invoke_impl = callbacks.create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
7929 if (callbacks.init_delegate)
7930 callbacks.init_delegate (delegate);
7935 * mono_delegate_ctor:
7936 * @this: pointer to an uninitialized delegate object
7937 * @target: target object
7938 * @addr: pointer to native code
7939 * @error: set on error.
7941 * This is used to initialize a delegate.
7942 * On failure returns FALSE and sets @error.
7945 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoError *error)
7947 MONO_REQ_GC_UNSAFE_MODE;
7949 mono_error_init (error);
7950 MonoDomain *domain = mono_domain_get ();
7952 MonoMethod *method = NULL;
7956 ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
7958 if (!ji && domain != mono_get_root_domain ())
7959 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
7961 method = mono_jit_info_get_method (ji);
7962 g_assert (!mono_class_is_gtd (method->klass));
7965 return mono_delegate_ctor_with_method (this_obj, target, addr, method, error);
7969 * mono_method_call_message_new:
7970 * @method: method to encapsulate
7971 * @params: parameters to the method
7972 * @invoke: optional, delegate invoke.
7973 * @cb: async callback delegate.
7974 * @state: state passed to the async callback.
7975 * @error: set on error.
7977 * Translates arguments pointers into a MonoMethodMessage.
7978 * On failure returns NULL and sets @error.
7981 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
7982 MonoDelegate **cb, MonoObject **state, MonoError *error)
7984 MONO_REQ_GC_UNSAFE_MODE;
7986 mono_error_init (error);
7988 MonoDomain *domain = mono_domain_get ();
7989 MonoMethodSignature *sig = mono_method_signature (method);
7990 MonoMethodMessage *msg;
7993 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
7994 return_val_if_nok (error, NULL);
7997 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, error);
7998 return_val_if_nok (error, NULL);
7999 mono_message_init (domain, msg, rm, NULL, error);
8000 return_val_if_nok (error, NULL);
8001 count = sig->param_count - 2;
8003 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
8004 return_val_if_nok (error, NULL);
8005 mono_message_init (domain, msg, rm, NULL, error);
8006 return_val_if_nok (error, NULL);
8007 count = sig->param_count;
8010 for (i = 0; i < count; i++) {
8015 if (sig->params [i]->byref)
8016 vpos = *((gpointer *)params [i]);
8020 klass = mono_class_from_mono_type (sig->params [i]);
8022 if (klass->valuetype) {
8023 arg = mono_value_box_checked (domain, klass, vpos, error);
8024 return_val_if_nok (error, NULL);
8026 arg = *((MonoObject **)vpos);
8028 mono_array_setref (msg->args, i, arg);
8031 if (cb != NULL && state != NULL) {
8032 *cb = *((MonoDelegate **)params [i]);
8034 *state = *((MonoObject **)params [i]);
8041 * mono_method_return_message_restore:
8043 * Restore results from message based processing back to arguments pointers
8046 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args, MonoError *error)
8048 MONO_REQ_GC_UNSAFE_MODE;
8050 mono_error_init (error);
8052 MonoMethodSignature *sig = mono_method_signature (method);
8053 int i, j, type, size, out_len;
8055 if (out_args == NULL)
8057 out_len = mono_array_length (out_args);
8061 for (i = 0, j = 0; i < sig->param_count; i++) {
8062 MonoType *pt = sig->params [i];
8067 mono_error_set_execution_engine (error, "The proxy call returned an incorrect number of output arguments");
8071 arg = (char *)mono_array_get (out_args, gpointer, j);
8074 g_assert (type != MONO_TYPE_VOID);
8076 if (MONO_TYPE_IS_REFERENCE (pt)) {
8077 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
8080 MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
8081 size = mono_class_value_size (klass, NULL);
8082 if (klass->has_references)
8083 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
8085 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
8087 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
8088 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
8097 #ifndef DISABLE_REMOTING
8100 * mono_load_remote_field:
8101 * @this: pointer to an object
8102 * @klass: klass of the object containing @field
8103 * @field: the field to load
8104 * @res: a storage to store the result
8106 * This method is called by the runtime on attempts to load fields of
8107 * transparent proxy objects. @this points to such TP, @klass is the class of
8108 * the object containing @field. @res is a storage location which can be
8109 * used to store the result.
8111 * Returns: an address pointing to the value of field.
8114 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
8117 gpointer result = mono_load_remote_field_checked (this_obj, klass, field, res, &error);
8118 mono_error_cleanup (&error);
8123 * mono_load_remote_field_checked:
8124 * @this: pointer to an object
8125 * @klass: klass of the object containing @field
8126 * @field: the field to load
8127 * @res: a storage to store the result
8128 * @error: set on error
8130 * This method is called by the runtime on attempts to load fields of
8131 * transparent proxy objects. @this points to such TP, @klass is the class of
8132 * the object containing @field. @res is a storage location which can be
8133 * used to store the result.
8135 * Returns: an address pointing to the value of field. On failure returns NULL and sets @error.
8138 mono_load_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res, MonoError *error)
8140 MONO_REQ_GC_UNSAFE_MODE;
8142 static MonoMethod *getter = NULL;
8144 mono_error_init (error);
8146 MonoDomain *domain = mono_domain_get ();
8147 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8148 MonoClass *field_class;
8149 MonoMethodMessage *msg;
8150 MonoArray *out_args;
8154 g_assert (mono_object_is_transparent_proxy (this_obj));
8155 g_assert (res != NULL);
8157 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8158 mono_field_get_value (tp->rp->unwrapped_server, field, res);
8163 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
8165 mono_error_set_not_supported (error, "Linked away.");
8170 field_class = mono_class_from_mono_type (field->type);
8172 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8173 return_val_if_nok (error, NULL);
8174 out_args = mono_array_new_checked (domain, mono_defaults.object_class, 1, error);
8175 return_val_if_nok (error, NULL);
8176 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, error);
8177 return_val_if_nok (error, NULL);
8178 mono_message_init (domain, msg, rm, out_args, error);
8179 return_val_if_nok (error, NULL);
8181 full_name = mono_type_get_full_name (klass);
8182 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
8183 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
8186 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8187 return_val_if_nok (error, NULL);
8190 mono_error_set_exception_instance (error, (MonoException *)exc);
8194 if (mono_array_length (out_args) == 0)
8197 mono_gc_wbarrier_generic_store (res, mono_array_get (out_args, MonoObject *, 0));
8199 if (field_class->valuetype) {
8200 return ((char *)*res) + sizeof (MonoObject);
8206 * mono_load_remote_field_new:
8211 * Missing documentation.
8214 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
8218 MonoObject *result = mono_load_remote_field_new_checked (this_obj, klass, field, &error);
8219 mono_error_cleanup (&error);
8224 * mono_load_remote_field_new_checked:
8225 * @this: pointer to an object
8226 * @klass: klass of the object containing @field
8227 * @field: the field to load
8228 * @error: set on error.
8230 * This method is called by the runtime on attempts to load fields of
8231 * transparent proxy objects. @this points to such TP, @klass is the class of
8232 * the object containing @field.
8234 * Returns: a freshly allocated object containing the value of the field. On failure returns NULL and sets @error.
8237 mono_load_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoError *error)
8239 MONO_REQ_GC_UNSAFE_MODE;
8241 mono_error_init (error);
8243 static MonoMethod *tp_load = NULL;
8245 g_assert (mono_object_is_transparent_proxy (this_obj));
8248 tp_load = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "LoadRemoteFieldNew", -1);
8250 mono_error_set_not_supported (error, "Linked away.");
8255 /* MonoType *type = mono_class_get_type (klass); */
8261 return mono_runtime_invoke_checked (tp_load, this_obj, args, error);
8265 * mono_store_remote_field:
8266 * @this_obj: pointer to an object
8267 * @klass: klass of the object containing @field
8268 * @field: the field to load
8269 * @val: the value/object to store
8271 * This method is called by the runtime on attempts to store fields of
8272 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
8273 * the object containing @field. @val is the new value to store in @field.
8276 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
8279 (void) mono_store_remote_field_checked (this_obj, klass, field, val, &error);
8280 mono_error_cleanup (&error);
8284 * mono_store_remote_field_checked:
8285 * @this_obj: pointer to an object
8286 * @klass: klass of the object containing @field
8287 * @field: the field to load
8288 * @val: the value/object to store
8289 * @error: set on error
8291 * This method is called by the runtime on attempts to store fields of
8292 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
8293 * the object containing @field. @val is the new value to store in @field.
8295 * Returns: on success returns TRUE, on failure returns FALSE and sets @error.
8298 mono_store_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val, MonoError *error)
8301 MONO_REQ_GC_UNSAFE_MODE;
8303 mono_error_init (error);
8305 MonoDomain *domain = mono_domain_get ();
8306 MonoClass *field_class;
8309 g_assert (mono_object_is_transparent_proxy (this_obj));
8311 field_class = mono_class_from_mono_type (field->type);
8313 if (field_class->valuetype) {
8314 arg = mono_value_box_checked (domain, field_class, val, error);
8315 return_val_if_nok (error, FALSE);
8317 arg = *((MonoObject**)val);
8320 return mono_store_remote_field_new_checked (this_obj, klass, field, arg, error);
8324 * mono_store_remote_field_new:
8330 * Missing documentation
8333 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
8336 (void) mono_store_remote_field_new_checked (this_obj, klass, field, arg, &error);
8337 mono_error_cleanup (&error);
8341 * mono_store_remote_field_new_checked:
8348 * Missing documentation
8351 mono_store_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg, MonoError *error)
8353 MONO_REQ_GC_UNSAFE_MODE;
8355 static MonoMethod *tp_store = NULL;
8357 mono_error_init (error);
8359 g_assert (mono_object_is_transparent_proxy (this_obj));
8362 tp_store = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "StoreRemoteField", -1);
8364 mono_error_set_not_supported (error, "Linked away.");
8374 mono_runtime_invoke_checked (tp_store, this_obj, args, error);
8375 return is_ok (error);
8380 * mono_create_ftnptr:
8382 * Given a function address, create a function descriptor for it.
8383 * This is only needed on some platforms.
8386 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
8388 return callbacks.create_ftnptr (domain, addr);
8392 * mono_get_addr_from_ftnptr:
8394 * Given a pointer to a function descriptor, return the function address.
8395 * This is only needed on some platforms.
8398 mono_get_addr_from_ftnptr (gpointer descr)
8400 return callbacks.get_addr_from_ftnptr (descr);
8404 * mono_string_chars:
8407 * Returns a pointer to the UCS16 characters stored in the MonoString
8410 mono_string_chars (MonoString *s)
8412 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
8418 * mono_string_length:
8421 * Returns the lenght in characters of the string
8424 mono_string_length (MonoString *s)
8426 MONO_REQ_GC_UNSAFE_MODE;
8432 * mono_array_length:
8433 * @array: a MonoArray*
8435 * Returns the total number of elements in the array. This works for
8436 * both vectors and multidimensional arrays.
8439 mono_array_length (MonoArray *array)
8441 MONO_REQ_GC_UNSAFE_MODE;
8443 return array->max_length;
8447 * mono_array_addr_with_size:
8448 * @array: a MonoArray*
8449 * @size: size of the array elements
8450 * @idx: index into the array
8452 * Use this function to obtain the address for the @idx item on the
8453 * @array containing elements of size @size.
8455 * This method performs no bounds checking or type checking.
8457 * Returns the address of the @idx element in the array.
8460 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
8462 MONO_REQ_GC_UNSAFE_MODE;
8464 return ((char*)(array)->vector) + size * idx;
8469 mono_glist_to_array (GList *list, MonoClass *eclass, MonoError *error)
8471 MonoDomain *domain = mono_domain_get ();
8475 mono_error_init (error);
8479 len = g_list_length (list);
8480 res = mono_array_new_checked (domain, eclass, len, error);
8481 return_val_if_nok (error, NULL);
8483 for (i = 0; list; list = list->next, i++)
8484 mono_array_set (res, gpointer, i, list->data);
8491 * The following section is purely to declare prototypes and
8492 * document the API, as these C files are processed by our
8498 * @array: array to alter
8499 * @element_type: A C type name, this macro will use the sizeof(type) to determine the element size
8500 * @index: index into the array
8501 * @value: value to set
8503 * Value Type version: This sets the @index's element of the @array
8504 * with elements of size sizeof(type) to the provided @value.
8506 * This macro does not attempt to perform type checking or bounds checking.
8508 * Use this to set value types in a `MonoArray`.
8510 void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
8515 * mono_array_setref:
8516 * @array: array to alter
8517 * @index: index into the array
8518 * @value: value to set
8520 * Reference Type version: This sets the @index's element of the
8521 * @array with elements of size sizeof(type) to the provided @value.
8523 * This macro does not attempt to perform type checking or bounds checking.
8525 * Use this to reference types in a `MonoArray`.
8527 void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
8533 * @array: array on which to operate on
8534 * @element_type: C element type (example: MonoString *, int, MonoObject *)
8535 * @index: index into the array
8537 * Use this macro to retrieve the @index element of an @array and
8538 * extract the value assuming that the elements of the array match
8539 * the provided type value.
8541 * This method can be used with both arrays holding value types and
8542 * reference types. For reference types, the @type parameter should
8543 * be a `MonoObject*` or any subclass of it, like `MonoString*`.
8545 * This macro does not attempt to perform type checking or bounds checking.
8547 * Returns: The element at the @index position in the @array.
8549 Type mono_array_get (MonoArray *array, Type element_type, uintptr_t index)