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/threads.h>
35 #include <mono/metadata/threads-types.h>
36 #include <mono/metadata/environment.h>
37 #include "mono/metadata/profiler-private.h"
38 #include "mono/metadata/security-manager.h"
39 #include "mono/metadata/mono-debug-debugger.h"
40 #include <mono/metadata/verify-internals.h>
41 #include <mono/metadata/reflection-internals.h>
42 #include <mono/metadata/w32event.h>
43 #include <mono/utils/strenc.h>
44 #include <mono/utils/mono-counters.h>
45 #include <mono/utils/mono-error-internals.h>
46 #include <mono/utils/mono-memory-model.h>
47 #include <mono/utils/checked-build.h>
48 #include <mono/utils/mono-threads.h>
49 #include <mono/utils/mono-threads-coop.h>
50 #include "cominterop.h"
51 #include <mono/utils/w32api.h>
54 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error);
57 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error);
60 free_main_args (void);
63 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error);
66 array_full_copy_unchecked_size (MonoArray *src, MonoArray *dest, MonoClass *klass, uintptr_t size);
69 class_get_virtual_method (MonoClass *klass, MonoMethod *method, gboolean is_proxy, MonoError *error);
71 /* Class lazy loading functions */
72 static GENERATE_GET_CLASS_WITH_CACHE (pointer, System.Reflection, "Pointer")
73 static GENERATE_GET_CLASS_WITH_CACHE (remoting_services, System.Runtime.Remoting, "RemotingServices")
74 static GENERATE_GET_CLASS_WITH_CACHE (unhandled_exception_event_args, System, "UnhandledExceptionEventArgs")
75 static GENERATE_GET_CLASS_WITH_CACHE (sta_thread_attribute, System, "STAThreadAttribute")
76 static GENERATE_GET_CLASS_WITH_CACHE (activation_services, System.Runtime.Remoting.Activation, "ActivationServices")
79 #define ldstr_lock() mono_os_mutex_lock (&ldstr_section)
80 #define ldstr_unlock() mono_os_mutex_unlock (&ldstr_section)
81 static mono_mutex_t ldstr_section;
85 * mono_runtime_object_init:
86 * @this_obj: the object to initialize
88 * This function calls the zero-argument constructor (which must
89 * exist) for the given object.
92 mono_runtime_object_init (MonoObject *this_obj)
95 mono_runtime_object_init_checked (this_obj, &error);
96 mono_error_assert_ok (&error);
100 * mono_runtime_object_init_checked:
101 * @this_obj: the object to initialize
102 * @error: set on error.
104 * This function calls the zero-argument constructor (which must
105 * exist) for the given object and returns TRUE on success, or FALSE
106 * on error and sets @error.
109 mono_runtime_object_init_checked (MonoObject *this_obj, MonoError *error)
111 MONO_REQ_GC_UNSAFE_MODE;
113 MonoMethod *method = NULL;
114 MonoClass *klass = this_obj->vtable->klass;
116 mono_error_init (error);
117 method = mono_class_get_method_from_name (klass, ".ctor", 0);
119 g_error ("Could not lookup zero argument constructor for class %s", mono_type_get_full_name (klass));
121 if (method->klass->valuetype)
122 this_obj = (MonoObject *)mono_object_unbox (this_obj);
124 mono_runtime_invoke_checked (method, this_obj, NULL, error);
125 return is_ok (error);
128 /* The pseudo algorithm for type initialization from the spec
129 Note it doesn't say anything about domains - only threads.
131 2. If the type is initialized you are done.
132 2.1. If the type is not yet initialized, try to take an
134 2.2. If successful, record this thread as responsible for
135 initializing the type and proceed to step 2.3.
136 2.2.1. If not, see whether this thread or any thread
137 waiting for this thread to complete already holds the lock.
138 2.2.2. If so, return since blocking would create a deadlock. This thread
139 will now see an incompletely initialized state for the type,
140 but no deadlock will arise.
141 2.2.3 If not, block until the type is initialized then return.
142 2.3 Initialize the parent type and then all interfaces implemented
144 2.4 Execute the type initialization code for this type.
145 2.5 Mark the type as initialized, release the initialization lock,
146 awaken any threads waiting for this type to be initialized,
153 MonoNativeThreadId initializing_tid;
154 guint32 waiting_count;
157 /* condvar used to wait for 'done' becoming TRUE */
159 } TypeInitializationLock;
161 /* for locking access to type_initialization_hash and blocked_thread_hash */
162 static MonoCoopMutex type_initialization_section;
165 mono_type_initialization_lock (void)
167 /* The critical sections protected by this lock in mono_runtime_class_init_full () can block */
168 mono_coop_mutex_lock (&type_initialization_section);
172 mono_type_initialization_unlock (void)
174 mono_coop_mutex_unlock (&type_initialization_section);
178 mono_type_init_lock (TypeInitializationLock *lock)
180 MONO_REQ_GC_NEUTRAL_MODE;
182 mono_coop_mutex_lock (&lock->mutex);
186 mono_type_init_unlock (TypeInitializationLock *lock)
188 mono_coop_mutex_unlock (&lock->mutex);
191 /* from vtable to lock */
192 static GHashTable *type_initialization_hash;
194 /* from thread id to thread id being waited on */
195 static GHashTable *blocked_thread_hash;
198 static MonoThread *main_thread;
200 /* Functions supplied by the runtime */
201 static MonoRuntimeCallbacks callbacks;
204 * mono_thread_set_main:
205 * @thread: thread to set as the main thread
207 * This function can be used to instruct the runtime to treat @thread
208 * as the main thread, ie, the thread that would normally execute the Main()
209 * method. This basically means that at the end of @thread, the runtime will
210 * wait for the existing foreground threads to quit and other such details.
213 mono_thread_set_main (MonoThread *thread)
215 MONO_REQ_GC_UNSAFE_MODE;
217 static gboolean registered = FALSE;
220 MONO_GC_REGISTER_ROOT_SINGLE (main_thread, MONO_ROOT_SOURCE_THREADING, "main thread object");
224 main_thread = thread;
228 mono_thread_get_main (void)
230 MONO_REQ_GC_UNSAFE_MODE;
236 mono_type_initialization_init (void)
238 mono_coop_mutex_init_recursive (&type_initialization_section);
239 type_initialization_hash = g_hash_table_new (NULL, NULL);
240 blocked_thread_hash = g_hash_table_new (NULL, NULL);
241 mono_os_mutex_init_recursive (&ldstr_section);
245 mono_type_initialization_cleanup (void)
248 /* This is causing race conditions with
249 * mono_release_type_locks
251 mono_coop_mutex_destroy (&type_initialization_section);
252 g_hash_table_destroy (type_initialization_hash);
253 type_initialization_hash = NULL;
255 mono_os_mutex_destroy (&ldstr_section);
256 g_hash_table_destroy (blocked_thread_hash);
257 blocked_thread_hash = NULL;
263 * get_type_init_exception_for_vtable:
265 * Return the stored type initialization exception for VTABLE.
267 static MonoException*
268 get_type_init_exception_for_vtable (MonoVTable *vtable)
270 MONO_REQ_GC_UNSAFE_MODE;
273 MonoDomain *domain = vtable->domain;
274 MonoClass *klass = vtable->klass;
278 if (!vtable->init_failed)
279 g_error ("Trying to get the init exception for a non-failed vtable of class %s", mono_type_get_full_name (klass));
282 * If the initializing thread was rudely aborted, the exception is not stored
286 mono_domain_lock (domain);
287 if (domain->type_init_exception_hash)
288 ex = (MonoException *)mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
289 mono_domain_unlock (domain);
292 if (klass->name_space && *klass->name_space)
293 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
295 full_name = g_strdup (klass->name);
296 ex = mono_get_exception_type_initialization_checked (full_name, NULL, &error);
298 return_val_if_nok (&error, NULL);
305 * mono_runtime_class_init:
306 * @vtable: vtable that needs to be initialized
308 * This routine calls the class constructor for @vtable.
311 mono_runtime_class_init (MonoVTable *vtable)
313 MONO_REQ_GC_UNSAFE_MODE;
316 mono_runtime_class_init_full (vtable, &error);
317 mono_error_assert_ok (&error);
321 * Returns TRUE if the lock was freed.
322 * LOCKING: Caller should hold type_initialization_lock.
325 unref_type_lock (TypeInitializationLock *lock)
327 --lock->waiting_count;
328 if (lock->waiting_count == 0) {
329 mono_coop_mutex_destroy (&lock->mutex);
330 mono_coop_cond_destroy (&lock->cond);
339 * mono_runtime_class_init_full:
340 * @vtable that neeeds to be initialized
341 * @error set on error
343 * returns TRUE if class constructor .cctor has been initialized successfully, or FALSE otherwise and sets @error.
347 mono_runtime_class_init_full (MonoVTable *vtable, MonoError *error)
349 MONO_REQ_GC_UNSAFE_MODE;
351 MonoMethod *method = NULL;
354 MonoDomain *domain = vtable->domain;
355 TypeInitializationLock *lock;
356 MonoNativeThreadId tid;
357 int do_initialization = 0;
358 MonoDomain *last_domain = NULL;
359 MonoException * pending_tae = NULL;
361 mono_error_init (error);
363 if (vtable->initialized)
366 klass = vtable->klass;
368 if (!klass->image->checked_module_cctor) {
369 mono_image_check_for_module_cctor (klass->image);
370 if (klass->image->has_module_cctor) {
371 MonoClass *module_klass;
372 MonoVTable *module_vtable;
374 module_klass = mono_class_get_checked (klass->image, MONO_TOKEN_TYPE_DEF | 1, error);
379 module_vtable = mono_class_vtable_full (vtable->domain, module_klass, error);
382 if (!mono_runtime_class_init_full (module_vtable, error))
386 method = mono_class_get_cctor (klass);
388 vtable->initialized = 1;
392 tid = mono_native_thread_id_get ();
395 * Due some preprocessing inside a global lock. If we are the first thread
396 * trying to initialize this class, create a separate lock+cond var, and
397 * acquire it before leaving the global lock. The other threads will wait
401 mono_type_initialization_lock ();
402 /* double check... */
403 if (vtable->initialized) {
404 mono_type_initialization_unlock ();
407 if (vtable->init_failed) {
408 mono_type_initialization_unlock ();
410 /* The type initialization already failed once, rethrow the same exception */
411 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
414 lock = (TypeInitializationLock *)g_hash_table_lookup (type_initialization_hash, vtable);
416 /* This thread will get to do the initialization */
417 if (mono_domain_get () != domain) {
418 /* Transfer into the target domain */
419 last_domain = mono_domain_get ();
420 if (!mono_domain_set (domain, FALSE)) {
421 vtable->initialized = 1;
422 mono_type_initialization_unlock ();
423 mono_error_set_exception_instance (error, mono_get_exception_appdomain_unloaded ());
427 lock = (TypeInitializationLock *)g_malloc0 (sizeof (TypeInitializationLock));
428 mono_coop_mutex_init_recursive (&lock->mutex);
429 mono_coop_cond_init (&lock->cond);
430 lock->initializing_tid = tid;
431 lock->waiting_count = 1;
433 /* grab the vtable lock while this thread still owns type_initialization_section */
434 /* This is why type_initialization_lock needs to enter blocking mode */
435 mono_type_init_lock (lock);
436 g_hash_table_insert (type_initialization_hash, vtable, lock);
437 do_initialization = 1;
440 TypeInitializationLock *pending_lock;
442 if (mono_native_thread_id_equals (lock->initializing_tid, tid)) {
443 mono_type_initialization_unlock ();
446 /* see if the thread doing the initialization is already blocked on this thread */
447 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (lock->initializing_tid));
448 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
449 if (mono_native_thread_id_equals (pending_lock->initializing_tid, tid)) {
450 if (!pending_lock->done) {
451 mono_type_initialization_unlock ();
454 /* the thread doing the initialization is blocked on this thread,
455 but on a lock that has already been freed. It just hasn't got
460 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (pending_lock->initializing_tid));
462 ++lock->waiting_count;
463 /* record the fact that we are waiting on the initializing thread */
464 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
466 mono_type_initialization_unlock ();
468 if (do_initialization) {
469 MonoException *exc = NULL;
471 /* We are holding the per-vtable lock, do the actual initialization */
473 mono_threads_begin_abort_protected_block ();
474 mono_runtime_try_invoke (method, NULL, NULL, (MonoObject**) &exc, error);
475 gboolean got_pending_interrupt = mono_threads_end_abort_protected_block ();
477 //exception extracted, error will be set to the right value later
478 if (exc == NULL && !mono_error_ok (error))//invoking failed but exc was not set
479 exc = mono_error_convert_to_exception (error);
481 mono_error_cleanup (error);
483 mono_error_init (error);
485 /* If the initialization failed, mark the class as unusable. */
486 /* Avoid infinite loops */
488 (klass->image == mono_defaults.corlib &&
489 !strcmp (klass->name_space, "System") &&
490 !strcmp (klass->name, "TypeInitializationException")))) {
491 vtable->init_failed = 1;
493 if (klass->name_space && *klass->name_space)
494 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
496 full_name = g_strdup (klass->name);
498 MonoException *exc_to_throw = mono_get_exception_type_initialization_checked (full_name, exc, error);
501 mono_error_assert_ok (error); //We can't recover from this, no way to fail a type we can't alloc a failure.
504 * Store the exception object so it could be thrown on subsequent
507 mono_domain_lock (domain);
508 if (!domain->type_init_exception_hash)
509 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");
510 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
511 mono_domain_unlock (domain);
515 mono_domain_set (last_domain, TRUE);
516 /* Signal to the other threads that we are done */
518 mono_coop_cond_broadcast (&lock->cond);
520 mono_type_init_unlock (lock);
522 //This can happen if the cctor self-aborts
523 if (exc && mono_object_class (exc) == mono_defaults.threadabortexception_class)
526 //TAEs are blocked around .cctors, they must escape as soon as no cctor is left to run.
527 if (!pending_tae && got_pending_interrupt)
528 pending_tae = mono_thread_try_resume_interruption ();
530 /* this just blocks until the initializing thread is done */
531 mono_type_init_lock (lock);
533 mono_coop_cond_wait (&lock->cond, &lock->mutex);
534 mono_type_init_unlock (lock);
537 /* Do cleanup and setting vtable->initialized inside the global lock again */
538 mono_type_initialization_lock ();
539 if (!do_initialization)
540 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
541 gboolean deleted = unref_type_lock (lock);
543 g_hash_table_remove (type_initialization_hash, vtable);
544 /* Have to set this here since we check it inside the global lock */
545 if (do_initialization && !vtable->init_failed)
546 vtable->initialized = 1;
547 mono_type_initialization_unlock ();
551 mono_error_set_exception_instance (error, pending_tae);
552 else if (vtable->init_failed) {
553 /* Either we were the initializing thread or we waited for the initialization */
554 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
561 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
563 MONO_REQ_GC_NEUTRAL_MODE;
565 MonoVTable *vtable = (MonoVTable*)key;
567 TypeInitializationLock *lock = (TypeInitializationLock*) value;
568 if (mono_native_thread_id_equals (lock->initializing_tid, MONO_UINT_TO_NATIVE_THREAD_ID (GPOINTER_TO_UINT (user))) && !lock->done) {
571 * Have to set this since it cannot be set by the normal code in
572 * mono_runtime_class_init (). In this case, the exception object is not stored,
573 * and get_type_init_exception_for_class () needs to be aware of this.
575 vtable->init_failed = 1;
576 mono_coop_cond_broadcast (&lock->cond);
577 mono_type_init_unlock (lock);
578 gboolean deleted = unref_type_lock (lock);
586 mono_release_type_locks (MonoInternalThread *thread)
588 MONO_REQ_GC_UNSAFE_MODE;
590 mono_type_initialization_lock ();
591 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, GUINT_TO_POINTER (thread->tid));
592 mono_type_initialization_unlock ();
595 #ifndef DISABLE_REMOTING
598 create_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error)
600 if (!callbacks.create_remoting_trampoline)
601 g_error ("remoting not installed");
602 return callbacks.create_remoting_trampoline (domain, method, target, error);
607 static MonoImtTrampolineBuilder imt_trampoline_builder;
608 static gboolean always_build_imt_trampolines;
610 #if (MONO_IMT_SIZE > 32)
611 #error "MONO_IMT_SIZE cannot be larger than 32"
615 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
617 memcpy (&callbacks, cbs, sizeof (*cbs));
620 MonoRuntimeCallbacks*
621 mono_get_runtime_callbacks (void)
627 mono_install_imt_trampoline_builder (MonoImtTrampolineBuilder func)
629 imt_trampoline_builder = func;
633 mono_set_always_build_imt_trampolines (gboolean value)
635 always_build_imt_trampolines = value;
639 * mono_compile_method:
640 * @method: The method to compile.
642 * This JIT-compiles the method, and returns the pointer to the native code
646 mono_compile_method (MonoMethod *method)
649 gpointer result = mono_compile_method_checked (method, &error);
650 mono_error_cleanup (&error);
655 * mono_compile_method:
656 * @method: The method to compile.
657 * @error: set on error.
659 * This JIT-compiles the method, and returns the pointer to the native code
660 * produced. On failure returns NULL and sets @error.
663 mono_compile_method_checked (MonoMethod *method, MonoError *error)
667 MONO_REQ_GC_NEUTRAL_MODE
669 mono_error_init (error);
671 g_assert (callbacks.compile_method);
672 res = callbacks.compile_method (method, error);
677 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper, MonoError *error)
681 MONO_REQ_GC_NEUTRAL_MODE;
683 mono_error_init (error);
684 res = callbacks.create_jump_trampoline (domain, method, add_sync_wrapper, error);
689 mono_runtime_create_delegate_trampoline (MonoClass *klass)
691 MONO_REQ_GC_NEUTRAL_MODE
693 g_assert (callbacks.create_delegate_trampoline);
694 return callbacks.create_delegate_trampoline (mono_domain_get (), klass);
698 * mono_runtime_free_method:
699 * @domain; domain where the method is hosted
700 * @method: method to release
702 * This routine is invoked to free the resources associated with
703 * a method that has been JIT compiled. This is used to discard
704 * methods that were used only temporarily (for example, used in marshalling)
708 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
710 MONO_REQ_GC_NEUTRAL_MODE
712 if (callbacks.free_method)
713 callbacks.free_method (domain, method);
715 mono_method_clear_object (domain, method);
717 mono_free_method (method);
721 * The vtables in the root appdomain are assumed to be reachable by other
722 * roots, and we don't use typed allocation in the other domains.
725 /* The sync block is no longer a GC pointer */
726 #define GC_HEADER_BITMAP (0)
728 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
731 compute_class_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
733 MONO_REQ_GC_NEUTRAL_MODE;
735 MonoClassField *field;
741 max_size = mono_class_data_size (klass) / sizeof (gpointer);
743 max_size = klass->instance_size / sizeof (gpointer);
744 if (max_size > size) {
745 g_assert (offset <= 0);
746 bitmap = (gsize *)g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
751 /*An Ephemeron cannot be marked by sgen*/
752 if (!static_fields && klass->image == mono_defaults.corlib && !strcmp ("Ephemeron", klass->name)) {
754 memset (bitmap, 0, size / 8);
759 for (p = klass; p != NULL; p = p->parent) {
760 gpointer iter = NULL;
761 while ((field = mono_class_get_fields (p, &iter))) {
765 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
767 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
770 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
773 /* FIXME: should not happen, flag as type load error */
774 if (field->type->byref)
777 if (static_fields && field->offset == -1)
781 pos = field->offset / sizeof (gpointer);
784 type = mono_type_get_underlying_type (field->type);
785 switch (type->type) {
788 case MONO_TYPE_FNPTR:
790 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
795 if (klass->image != mono_defaults.corlib)
798 case MONO_TYPE_STRING:
799 case MONO_TYPE_SZARRAY:
800 case MONO_TYPE_CLASS:
801 case MONO_TYPE_OBJECT:
802 case MONO_TYPE_ARRAY:
803 g_assert ((field->offset % sizeof(gpointer)) == 0);
805 g_assert (pos < size || pos <= max_size);
806 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
807 *max_set = MAX (*max_set, pos);
809 case MONO_TYPE_GENERICINST:
810 if (!mono_type_generic_inst_is_valuetype (type)) {
811 g_assert ((field->offset % sizeof(gpointer)) == 0);
813 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
814 *max_set = MAX (*max_set, pos);
819 case MONO_TYPE_VALUETYPE: {
820 MonoClass *fclass = mono_class_from_mono_type (field->type);
821 if (fclass->has_references) {
822 /* remove the object header */
823 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
837 case MONO_TYPE_BOOLEAN:
841 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
852 * mono_class_compute_bitmap:
854 * Mono internal function to compute a bitmap of reference fields in a class.
857 mono_class_compute_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
859 MONO_REQ_GC_NEUTRAL_MODE;
861 return compute_class_bitmap (klass, bitmap, size, offset, max_set, static_fields);
866 * similar to the above, but sets the bits in the bitmap for any non-ref field
867 * and ignores static fields
870 compute_class_non_ref_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset)
872 MonoClassField *field;
877 max_size = class->instance_size / sizeof (gpointer);
878 if (max_size >= size) {
879 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
882 for (p = class; p != NULL; p = p->parent) {
883 gpointer iter = NULL;
884 while ((field = mono_class_get_fields (p, &iter))) {
887 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
889 /* FIXME: should not happen, flag as type load error */
890 if (field->type->byref)
893 pos = field->offset / sizeof (gpointer);
896 type = mono_type_get_underlying_type (field->type);
897 switch (type->type) {
898 #if SIZEOF_VOID_P == 8
902 case MONO_TYPE_FNPTR:
907 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
908 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
909 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
912 #if SIZEOF_VOID_P == 4
916 case MONO_TYPE_FNPTR:
921 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
922 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
923 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
929 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
930 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
931 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
934 case MONO_TYPE_BOOLEAN:
937 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
939 case MONO_TYPE_STRING:
940 case MONO_TYPE_SZARRAY:
941 case MONO_TYPE_CLASS:
942 case MONO_TYPE_OBJECT:
943 case MONO_TYPE_ARRAY:
945 case MONO_TYPE_GENERICINST:
946 if (!mono_type_generic_inst_is_valuetype (type)) {
951 case MONO_TYPE_VALUETYPE: {
952 MonoClass *fclass = mono_class_from_mono_type (field->type);
953 /* remove the object header */
954 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
958 g_assert_not_reached ();
967 * mono_class_insecure_overlapping:
968 * check if a class with explicit layout has references and non-references
969 * fields overlapping.
971 * Returns: TRUE if it is insecure to load the type.
974 mono_class_insecure_overlapping (MonoClass *klass)
978 gsize default_bitmap [4] = {0};
980 gsize default_nrbitmap [4] = {0};
981 int i, insecure = FALSE;
984 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
985 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
987 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
988 int idx = i % (sizeof (bitmap [0]) * 8);
989 if (bitmap [idx] & nrbitmap [idx]) {
994 if (bitmap != default_bitmap)
996 if (nrbitmap != default_nrbitmap)
999 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
1007 ves_icall_string_alloc (int length)
1010 MonoString *str = mono_string_new_size_checked (mono_domain_get (), length, &error);
1011 mono_error_set_pending_exception (&error);
1016 /* LOCKING: Acquires the loader lock */
1018 mono_class_compute_gc_descriptor (MonoClass *klass)
1020 MONO_REQ_GC_NEUTRAL_MODE;
1024 gsize default_bitmap [4] = {0};
1025 static gboolean gcj_inited = FALSE;
1026 MonoGCDescriptor gc_descr;
1029 mono_loader_lock ();
1031 mono_register_jit_icall (ves_icall_object_new_fast, "ves_icall_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
1032 mono_register_jit_icall (ves_icall_string_alloc, "ves_icall_string_alloc", mono_create_icall_signature ("object int"), FALSE);
1035 mono_loader_unlock ();
1039 mono_class_init (klass);
1041 if (klass->gc_descr_inited)
1044 bitmap = default_bitmap;
1045 if (klass == mono_defaults.string_class) {
1046 gc_descr = mono_gc_make_descr_for_string (bitmap, 2);
1047 } else if (klass->rank) {
1048 mono_class_compute_gc_descriptor (klass->element_class);
1049 if (MONO_TYPE_IS_REFERENCE (&klass->element_class->byval_arg)) {
1051 gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
1052 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1053 class->name_space, class->name);*/
1055 /* remove the object header */
1056 bitmap = compute_class_bitmap (klass->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
1057 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));
1058 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1059 class->name_space, class->name);*/
1060 if (bitmap != default_bitmap)
1064 /*static int count = 0;
1067 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1068 gc_descr = mono_gc_make_descr_for_object (bitmap, max_set + 1, klass->instance_size);
1070 if (class->gc_descr == MONO_GC_DESCRIPTOR_NULL)
1071 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
1073 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
1074 if (bitmap != default_bitmap)
1078 /* Publish the data */
1079 mono_loader_lock ();
1080 klass->gc_descr = gc_descr;
1081 mono_memory_barrier ();
1082 klass->gc_descr_inited = TRUE;
1083 mono_loader_unlock ();
1087 * field_is_special_static:
1088 * @fklass: The MonoClass to look up.
1089 * @field: The MonoClassField describing the field.
1091 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1092 * SPECIAL_STATIC_NONE otherwise.
1095 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1097 MONO_REQ_GC_NEUTRAL_MODE;
1100 MonoCustomAttrInfo *ainfo;
1102 ainfo = mono_custom_attrs_from_field_checked (fklass, field, &error);
1103 mono_error_cleanup (&error); /* FIXME don't swallow the error? */
1106 for (i = 0; i < ainfo->num_attrs; ++i) {
1107 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1108 if (klass->image == mono_defaults.corlib) {
1109 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1110 mono_custom_attrs_free (ainfo);
1111 return SPECIAL_STATIC_THREAD;
1113 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1114 mono_custom_attrs_free (ainfo);
1115 return SPECIAL_STATIC_CONTEXT;
1119 mono_custom_attrs_free (ainfo);
1120 return SPECIAL_STATIC_NONE;
1123 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1124 #define mix(a,b,c) { \
1125 a -= c; a ^= rot(c, 4); c += b; \
1126 b -= a; b ^= rot(a, 6); a += c; \
1127 c -= b; c ^= rot(b, 8); b += a; \
1128 a -= c; a ^= rot(c,16); c += b; \
1129 b -= a; b ^= rot(a,19); a += c; \
1130 c -= b; c ^= rot(b, 4); b += a; \
1132 #define final(a,b,c) { \
1133 c ^= b; c -= rot(b,14); \
1134 a ^= c; a -= rot(c,11); \
1135 b ^= a; b -= rot(a,25); \
1136 c ^= b; c -= rot(b,16); \
1137 a ^= c; a -= rot(c,4); \
1138 b ^= a; b -= rot(a,14); \
1139 c ^= b; c -= rot(b,24); \
1143 * mono_method_get_imt_slot:
1145 * The IMT slot is embedded into AOTed code, so this must return the same value
1146 * for the same method across all executions. This means:
1147 * - pointers shouldn't be used as hash values.
1148 * - mono_metadata_str_hash () should be used for hashing strings.
1151 mono_method_get_imt_slot (MonoMethod *method)
1153 MONO_REQ_GC_NEUTRAL_MODE;
1155 MonoMethodSignature *sig;
1157 guint32 *hashes_start, *hashes;
1161 /* This can be used to stress tests the collision code */
1165 * We do this to simplify generic sharing. It will hurt
1166 * performance in cases where a class implements two different
1167 * instantiations of the same generic interface.
1168 * The code in build_imt_slots () depends on this.
1170 if (method->is_inflated)
1171 method = ((MonoMethodInflated*)method)->declaring;
1173 sig = mono_method_signature (method);
1174 hashes_count = sig->param_count + 4;
1175 hashes_start = (guint32 *)malloc (hashes_count * sizeof (guint32));
1176 hashes = hashes_start;
1178 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1179 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1180 method->klass->name_space, method->klass->name, method->name);
1183 /* Initialize hashes */
1184 hashes [0] = mono_metadata_str_hash (method->klass->name);
1185 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1186 hashes [2] = mono_metadata_str_hash (method->name);
1187 hashes [3] = mono_metadata_type_hash (sig->ret);
1188 for (i = 0; i < sig->param_count; i++) {
1189 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1192 /* Setup internal state */
1193 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1195 /* Handle most of the hashes */
1196 while (hashes_count > 3) {
1205 /* Handle the last 3 hashes (all the case statements fall through) */
1206 switch (hashes_count) {
1207 case 3 : c += hashes [2];
1208 case 2 : b += hashes [1];
1209 case 1 : a += hashes [0];
1211 case 0: /* nothing left to add */
1215 g_free (hashes_start);
1216 /* Report the result */
1217 return c % MONO_IMT_SIZE;
1226 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1227 MONO_REQ_GC_NEUTRAL_MODE;
1229 guint32 imt_slot = mono_method_get_imt_slot (method);
1230 MonoImtBuilderEntry *entry;
1232 if (slot_num >= 0 && imt_slot != slot_num) {
1233 /* we build just a single imt slot and this is not it */
1237 entry = (MonoImtBuilderEntry *)g_malloc0 (sizeof (MonoImtBuilderEntry));
1238 entry->key = method;
1239 entry->value.vtable_slot = vtable_slot;
1240 entry->next = imt_builder [imt_slot];
1241 if (imt_builder [imt_slot] != NULL) {
1242 entry->children = imt_builder [imt_slot]->children + 1;
1243 if (entry->children == 1) {
1244 mono_stats.imt_slots_with_collisions++;
1245 *imt_collisions_bitmap |= (1 << imt_slot);
1248 entry->children = 0;
1249 mono_stats.imt_used_slots++;
1251 imt_builder [imt_slot] = entry;
1254 char *method_name = mono_method_full_name (method, TRUE);
1255 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1256 method, method_name, imt_slot, vtable_slot, entry->children);
1257 g_free (method_name);
1264 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1266 MonoMethod *method = e->key;
1267 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1271 method->klass->name_space,
1272 method->klass->name,
1275 printf (" * %s: NULL\n", message);
1281 compare_imt_builder_entries (const void *p1, const void *p2) {
1282 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1283 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1285 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1289 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1291 MONO_REQ_GC_NEUTRAL_MODE;
1293 int count = end - start;
1294 int chunk_start = out_array->len;
1297 for (i = start; i < end; ++i) {
1298 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1299 item->key = sorted_array [i]->key;
1300 item->value = sorted_array [i]->value;
1301 item->has_target_code = sorted_array [i]->has_target_code;
1302 item->is_equals = TRUE;
1304 item->check_target_idx = out_array->len + 1;
1306 item->check_target_idx = 0;
1307 g_ptr_array_add (out_array, item);
1310 int middle = start + count / 2;
1311 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1313 item->key = sorted_array [middle]->key;
1314 item->is_equals = FALSE;
1315 g_ptr_array_add (out_array, item);
1316 imt_emit_ir (sorted_array, start, middle, out_array);
1317 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1323 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1324 MONO_REQ_GC_NEUTRAL_MODE;
1326 int number_of_entries = entries->children + 1;
1327 MonoImtBuilderEntry **sorted_array = (MonoImtBuilderEntry **)malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1328 GPtrArray *result = g_ptr_array_new ();
1329 MonoImtBuilderEntry *current_entry;
1332 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1333 sorted_array [i] = current_entry;
1335 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1337 /*for (i = 0; i < number_of_entries; i++) {
1338 print_imt_entry (" sorted array:", sorted_array [i], i);
1341 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1343 g_free (sorted_array);
1348 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1350 MONO_REQ_GC_NEUTRAL_MODE;
1352 if (imt_builder_entry != NULL) {
1353 if (imt_builder_entry->children == 0 && !fail_tramp && !always_build_imt_trampolines) {
1354 /* No collision, return the vtable slot contents */
1355 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1357 /* Collision, build the trampoline */
1358 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1361 result = imt_trampoline_builder (vtable, domain,
1362 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1363 for (i = 0; i < imt_ir->len; ++i)
1364 g_free (g_ptr_array_index (imt_ir, i));
1365 g_ptr_array_free (imt_ir, TRUE);
1377 static MonoImtBuilderEntry*
1378 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1381 * LOCKING: requires the loader and domain locks.
1385 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1387 MONO_REQ_GC_NEUTRAL_MODE;
1391 guint32 imt_collisions_bitmap = 0;
1392 MonoImtBuilderEntry **imt_builder = (MonoImtBuilderEntry **)calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1393 int method_count = 0;
1394 gboolean record_method_count_for_max_collisions = FALSE;
1395 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1398 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1400 for (i = 0; i < klass->interface_offsets_count; ++i) {
1401 MonoClass *iface = klass->interfaces_packed [i];
1402 int interface_offset = klass->interface_offsets_packed [i];
1403 int method_slot_in_interface, vt_slot;
1405 if (mono_class_has_variant_generic_params (iface))
1406 has_variant_iface = TRUE;
1408 mono_class_setup_methods (iface);
1409 vt_slot = interface_offset;
1410 int mcount = mono_class_get_method_count (iface);
1411 for (method_slot_in_interface = 0; method_slot_in_interface < mcount; method_slot_in_interface++) {
1414 if (slot_num >= 0 && mono_class_is_ginst (iface)) {
1416 * The imt slot of the method is the same as for its declaring method,
1417 * see the comment in mono_method_get_imt_slot (), so we can
1418 * avoid inflating methods which will be discarded by
1419 * add_imt_builder_entry anyway.
1421 method = mono_class_get_method_by_index (mono_class_get_generic_class (iface)->container_class, method_slot_in_interface);
1422 if (mono_method_get_imt_slot (method) != slot_num) {
1427 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1428 if (method->is_generic) {
1429 has_generic_virtual = TRUE;
1434 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1435 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1440 if (extra_interfaces) {
1441 int interface_offset = klass->vtable_size;
1443 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1444 MonoClass* iface = (MonoClass *)list_item->data;
1445 int method_slot_in_interface;
1446 int mcount = mono_class_get_method_count (iface);
1447 for (method_slot_in_interface = 0; method_slot_in_interface < mcount; method_slot_in_interface++) {
1448 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1450 if (method->is_generic)
1451 has_generic_virtual = TRUE;
1452 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1454 interface_offset += mcount;
1457 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1458 /* overwrite the imt slot only if we're building all the entries or if
1459 * we're building this specific one
1461 if (slot_num < 0 || i == slot_num) {
1462 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1465 if (imt_builder [i]) {
1466 MonoImtBuilderEntry *entry;
1468 /* Link entries with imt_builder [i] */
1469 for (entry = entries; entry->next; entry = entry->next) {
1471 MonoMethod *method = (MonoMethod*)entry->key;
1472 char *method_name = mono_method_full_name (method, TRUE);
1473 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1474 g_free (method_name);
1477 entry->next = imt_builder [i];
1478 entries->children += imt_builder [i]->children + 1;
1480 imt_builder [i] = entries;
1483 if (has_generic_virtual || has_variant_iface) {
1485 * There might be collisions later when the the trampoline is expanded.
1487 imt_collisions_bitmap |= (1 << i);
1490 * The IMT trampoline might be called with an instance of one of the
1491 * generic virtual methods, so has to fallback to the IMT trampoline.
1493 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline (vt, i));
1495 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1498 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1502 if (imt_builder [i] != NULL) {
1503 int methods_in_slot = imt_builder [i]->children + 1;
1504 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1505 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1506 record_method_count_for_max_collisions = TRUE;
1508 method_count += methods_in_slot;
1512 mono_stats.imt_number_of_methods += method_count;
1513 if (record_method_count_for_max_collisions) {
1514 mono_stats.imt_method_count_when_max_collisions = method_count;
1517 for (i = 0; i < MONO_IMT_SIZE; i++) {
1518 MonoImtBuilderEntry* entry = imt_builder [i];
1519 while (entry != NULL) {
1520 MonoImtBuilderEntry* next = entry->next;
1525 g_free (imt_builder);
1526 /* we OR the bitmap since we may build just a single imt slot at a time */
1527 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1531 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1532 MONO_REQ_GC_NEUTRAL_MODE;
1534 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1538 * mono_vtable_build_imt_slot:
1539 * @vtable: virtual object table struct
1540 * @imt_slot: slot in the IMT table
1542 * Fill the given @imt_slot in the IMT table of @vtable with
1543 * a trampoline or a trampoline for the case of collisions.
1544 * This is part of the internal mono API.
1546 * LOCKING: Take the domain lock.
1549 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1551 MONO_REQ_GC_NEUTRAL_MODE;
1553 gpointer *imt = (gpointer*)vtable;
1554 imt -= MONO_IMT_SIZE;
1555 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1557 /* no support for extra interfaces: the proxy objects will need
1558 * to build the complete IMT
1559 * Update and heck needs to ahppen inside the proper domain lock, as all
1560 * the changes made to a MonoVTable.
1562 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1563 mono_domain_lock (vtable->domain);
1564 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1565 if (!callbacks.imt_entry_inited (vtable, imt_slot))
1566 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1567 mono_domain_unlock (vtable->domain);
1568 mono_loader_unlock ();
1571 #define THUNK_THRESHOLD 10
1574 * mono_method_alloc_generic_virtual_trampoline:
1576 * @size: size in bytes
1578 * Allocs size bytes to be used for the code of a generic virtual
1579 * trampoline. It's either allocated from the domain's code manager or
1580 * reused from a previously invalidated piece.
1582 * LOCKING: The domain lock must be held.
1585 mono_method_alloc_generic_virtual_trampoline (MonoDomain *domain, int size)
1587 MONO_REQ_GC_NEUTRAL_MODE;
1589 static gboolean inited = FALSE;
1590 static int generic_virtual_trampolines_size = 0;
1593 mono_counters_register ("Generic virtual trampoline bytes",
1594 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_trampolines_size);
1597 generic_virtual_trampolines_size += size;
1599 return mono_domain_code_reserve (domain, size);
1602 typedef struct _GenericVirtualCase {
1606 struct _GenericVirtualCase *next;
1607 } GenericVirtualCase;
1610 * get_generic_virtual_entries:
1612 * Return IMT entries for the generic virtual method instances and
1613 * variant interface methods for vtable slot
1616 static MonoImtBuilderEntry*
1617 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1619 MONO_REQ_GC_NEUTRAL_MODE;
1621 GenericVirtualCase *list;
1622 MonoImtBuilderEntry *entries;
1624 mono_domain_lock (domain);
1625 if (!domain->generic_virtual_cases)
1626 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1628 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1631 for (; list; list = list->next) {
1632 MonoImtBuilderEntry *entry;
1634 if (list->count < THUNK_THRESHOLD)
1637 entry = g_new0 (MonoImtBuilderEntry, 1);
1638 entry->key = list->method;
1639 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1640 entry->has_target_code = 1;
1642 entry->children = entries->children + 1;
1643 entry->next = entries;
1647 mono_domain_unlock (domain);
1649 /* FIXME: Leaking memory ? */
1654 * mono_method_add_generic_virtual_invocation:
1656 * @vtable_slot: pointer to the vtable slot
1657 * @method: the inflated generic virtual method
1658 * @code: the method's code
1660 * Registers a call via unmanaged code to a generic virtual method
1661 * instantiation or variant interface method. If the number of calls reaches a threshold
1662 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1663 * virtual method trampoline.
1666 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1667 gpointer *vtable_slot,
1668 MonoMethod *method, gpointer code)
1670 MONO_REQ_GC_NEUTRAL_MODE;
1672 static gboolean inited = FALSE;
1673 static int num_added = 0;
1674 static int num_freed = 0;
1676 GenericVirtualCase *gvc, *list;
1677 MonoImtBuilderEntry *entries;
1681 mono_domain_lock (domain);
1682 if (!domain->generic_virtual_cases)
1683 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1686 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1687 mono_counters_register ("Freed IMT trampolines", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_freed);
1691 /* Check whether the case was already added */
1692 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1695 if (gvc->method == method)
1700 /* If not found, make a new one */
1702 gvc = (GenericVirtualCase *)mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1703 gvc->method = method;
1706 gvc->next = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1708 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1713 if (++gvc->count == THUNK_THRESHOLD) {
1714 gpointer *old_thunk = (void **)*vtable_slot;
1715 gpointer vtable_trampoline = NULL;
1716 gpointer imt_trampoline = NULL;
1718 if ((gpointer)vtable_slot < (gpointer)vtable) {
1719 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1720 int imt_slot = MONO_IMT_SIZE + displacement;
1722 /* Force the rebuild of the trampoline at the next call */
1723 imt_trampoline = callbacks.get_imt_trampoline (vtable, imt_slot);
1724 *vtable_slot = imt_trampoline;
1726 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline (vtable, (gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1728 entries = get_generic_virtual_entries (domain, vtable_slot);
1730 sorted = imt_sort_slot_entries (entries);
1732 *vtable_slot = imt_trampoline_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1736 MonoImtBuilderEntry *next = entries->next;
1741 for (i = 0; i < sorted->len; ++i)
1742 g_free (g_ptr_array_index (sorted, i));
1743 g_ptr_array_free (sorted, TRUE);
1745 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1750 mono_domain_unlock (domain);
1753 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error);
1756 * mono_class_vtable:
1757 * @domain: the application domain
1758 * @class: the class to initialize
1760 * VTables are domain specific because we create domain specific code, and
1761 * they contain the domain specific static class data.
1762 * On failure, NULL is returned, and class->exception_type is set.
1765 mono_class_vtable (MonoDomain *domain, MonoClass *klass)
1768 MonoVTable* vtable = mono_class_vtable_full (domain, klass, &error);
1769 mono_error_cleanup (&error);
1774 * mono_class_vtable_full:
1775 * @domain: the application domain
1776 * @class: the class to initialize
1777 * @error set on failure.
1779 * VTables are domain specific because we create domain specific code, and
1780 * they contain the domain specific static class data.
1783 mono_class_vtable_full (MonoDomain *domain, MonoClass *klass, MonoError *error)
1785 MONO_REQ_GC_UNSAFE_MODE;
1787 MonoClassRuntimeInfo *runtime_info;
1789 mono_error_init (error);
1793 if (mono_class_has_failure (klass)) {
1794 mono_error_set_for_class_failure (error, klass);
1798 /* this check can be inlined in jitted code, too */
1799 runtime_info = klass->runtime_info;
1800 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1801 return runtime_info->domain_vtables [domain->domain_id];
1802 return mono_class_create_runtime_vtable (domain, klass, error);
1806 * mono_class_try_get_vtable:
1807 * @domain: the application domain
1808 * @class: the class to initialize
1810 * This function tries to get the associated vtable from @class if
1811 * it was already created.
1814 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *klass)
1816 MONO_REQ_GC_NEUTRAL_MODE;
1818 MonoClassRuntimeInfo *runtime_info;
1822 runtime_info = klass->runtime_info;
1823 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1824 return runtime_info->domain_vtables [domain->domain_id];
1829 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1831 MONO_REQ_GC_NEUTRAL_MODE;
1833 size_t alloc_offset;
1836 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1837 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1838 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1840 if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1841 g_assert ((imt_table_bytes & 7) == 4);
1848 return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1852 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error)
1854 MONO_REQ_GC_UNSAFE_MODE;
1857 MonoClassRuntimeInfo *runtime_info, *old_info;
1858 MonoClassField *field;
1860 int i, vtable_slots;
1861 size_t imt_table_bytes;
1863 guint32 vtable_size, class_size;
1865 gpointer *interface_offsets;
1867 mono_error_init (error);
1869 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1870 mono_domain_lock (domain);
1871 runtime_info = klass->runtime_info;
1872 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1873 mono_domain_unlock (domain);
1874 mono_loader_unlock ();
1875 return runtime_info->domain_vtables [domain->domain_id];
1877 if (!klass->inited || mono_class_has_failure (klass)) {
1878 if (!mono_class_init (klass) || mono_class_has_failure (klass)) {
1879 mono_domain_unlock (domain);
1880 mono_loader_unlock ();
1881 mono_error_set_for_class_failure (error, klass);
1886 /* Array types require that their element type be valid*/
1887 if (klass->byval_arg.type == MONO_TYPE_ARRAY || klass->byval_arg.type == MONO_TYPE_SZARRAY) {
1888 MonoClass *element_class = klass->element_class;
1889 if (!element_class->inited)
1890 mono_class_init (element_class);
1892 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1893 if (!mono_class_has_failure (element_class) && !element_class->vtable_size)
1894 mono_class_setup_vtable (element_class);
1896 if (mono_class_has_failure (element_class)) {
1897 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1898 if (!mono_class_has_failure (klass))
1899 mono_class_set_type_load_failure (klass, "");
1900 mono_domain_unlock (domain);
1901 mono_loader_unlock ();
1902 mono_error_set_for_class_failure (error, klass);
1908 * For some classes, mono_class_init () already computed klass->vtable_size, and
1909 * that is all that is needed because of the vtable trampolines.
1911 if (!klass->vtable_size)
1912 mono_class_setup_vtable (klass);
1914 if (mono_class_is_ginst (klass) && !klass->vtable)
1915 mono_class_check_vtable_constraints (klass, NULL);
1917 /* Initialize klass->has_finalize */
1918 mono_class_has_finalizer (klass);
1920 if (mono_class_has_failure (klass)) {
1921 mono_domain_unlock (domain);
1922 mono_loader_unlock ();
1923 mono_error_set_for_class_failure (error, klass);
1927 vtable_slots = klass->vtable_size;
1928 /* we add an additional vtable slot to store the pointer to static field data only when needed */
1929 class_size = mono_class_data_size (klass);
1933 if (klass->interface_offsets_count) {
1934 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1935 mono_stats.imt_number_of_tables++;
1936 mono_stats.imt_tables_size += imt_table_bytes;
1938 imt_table_bytes = 0;
1941 vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
1943 mono_stats.used_class_count++;
1944 mono_stats.class_vtable_size += vtable_size;
1946 interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
1947 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1948 g_assert (!((gsize)vt & 7));
1951 vt->rank = klass->rank;
1952 vt->domain = domain;
1954 mono_class_compute_gc_descriptor (klass);
1956 * We can't use typed allocation in the non-root domains, since the
1957 * collector needs the GC descriptor stored in the vtable even after
1958 * the mempool containing the vtable is destroyed when the domain is
1959 * unloaded. An alternative might be to allocate vtables in the GC
1960 * heap, but this does not seem to work (it leads to crashes inside
1961 * libgc). If that approach is tried, two gc descriptors need to be
1962 * allocated for each class: one for the root domain, and one for all
1963 * other domains. The second descriptor should contain a bit for the
1964 * vtable field in MonoObject, since we can no longer assume the
1965 * vtable is reachable by other roots after the appdomain is unloaded.
1967 #ifdef HAVE_BOEHM_GC
1968 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1969 vt->gc_descr = MONO_GC_DESCRIPTOR_NULL;
1972 vt->gc_descr = klass->gc_descr;
1974 gc_bits = mono_gc_get_vtable_bits (klass);
1975 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
1977 vt->gc_bits = gc_bits;
1980 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
1981 if (klass->has_static_refs) {
1982 MonoGCDescriptor statics_gc_descr;
1984 gsize default_bitmap [4] = {0};
1987 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1988 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], klass->name_space, klass->name, class_size);*/
1989 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1990 vt->vtable [klass->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr, MONO_ROOT_SOURCE_STATIC, "managed static variables");
1991 mono_domain_add_class_static_data (domain, klass, vt->vtable [klass->vtable_size], NULL);
1992 if (bitmap != default_bitmap)
1995 vt->vtable [klass->vtable_size] = mono_domain_alloc0 (domain, class_size);
1997 vt->has_static_fields = TRUE;
1998 mono_stats.class_static_data_size += class_size;
2002 while ((field = mono_class_get_fields (klass, &iter))) {
2003 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2005 if (mono_field_is_deleted (field))
2007 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2008 gint32 special_static = klass->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (klass, field);
2009 if (special_static != SPECIAL_STATIC_NONE) {
2010 guint32 size, offset;
2012 gsize default_bitmap [4] = {0};
2017 if (mono_type_is_reference (field->type)) {
2018 default_bitmap [0] = 1;
2020 bitmap = default_bitmap;
2021 } else if (mono_type_is_struct (field->type)) {
2022 fclass = mono_class_from_mono_type (field->type);
2023 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
2024 numbits = max_set + 1;
2026 default_bitmap [0] = 0;
2028 bitmap = default_bitmap;
2030 size = mono_type_size (field->type, &align);
2031 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
2032 if (!domain->special_static_fields)
2033 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2034 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2035 if (bitmap != default_bitmap)
2038 * This marks the field as special static to speed up the
2039 * checks in mono_field_static_get/set_value ().
2045 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2046 MonoClass *fklass = mono_class_from_mono_type (field->type);
2047 const char *data = mono_field_get_data (field);
2049 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2050 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2051 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2054 if (fklass->valuetype) {
2055 memcpy (t, data, mono_class_value_size (fklass, NULL));
2057 /* it's a pointer type: add check */
2058 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2065 vt->max_interface_id = klass->max_interface_id;
2066 vt->interface_bitmap = klass->interface_bitmap;
2068 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2069 // class->name, klass->interface_offsets_count);
2071 /* Initialize vtable */
2072 if (callbacks.get_vtable_trampoline) {
2073 // This also covers the AOT case
2074 for (i = 0; i < klass->vtable_size; ++i) {
2075 vt->vtable [i] = callbacks.get_vtable_trampoline (vt, i);
2078 mono_class_setup_vtable (klass);
2080 for (i = 0; i < klass->vtable_size; ++i) {
2083 cm = klass->vtable [i];
2085 vt->vtable [i] = callbacks.create_jit_trampoline (domain, cm, error);
2086 if (!is_ok (error)) {
2087 mono_domain_unlock (domain);
2088 mono_loader_unlock ();
2095 if (imt_table_bytes) {
2096 /* Now that the vtable is full, we can actually fill up the IMT */
2097 for (i = 0; i < MONO_IMT_SIZE; ++i)
2098 interface_offsets [i] = callbacks.get_imt_trampoline (vt, i);
2102 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2103 * re-acquire them and check if another thread has created the vtable in the meantime.
2105 /* Special case System.MonoType to avoid infinite recursion */
2106 if (klass != mono_defaults.runtimetype_class) {
2107 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2108 if (!is_ok (error)) {
2109 mono_domain_unlock (domain);
2110 mono_loader_unlock ();
2114 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2115 /* This is unregistered in
2116 unregister_vtable_reflection_type() in
2118 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2121 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (klass));
2123 /* class_vtable_array keeps an array of created vtables
2125 g_ptr_array_add (domain->class_vtable_array, vt);
2126 /* klass->runtime_info is protected by the loader lock, both when
2127 * it it enlarged and when it is stored info.
2131 * Store the vtable in klass->runtime_info.
2132 * klass->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2134 mono_memory_barrier ();
2136 old_info = klass->runtime_info;
2137 if (old_info && old_info->max_domain >= domain->domain_id) {
2138 /* someone already created a large enough runtime info */
2139 old_info->domain_vtables [domain->domain_id] = vt;
2141 int new_size = domain->domain_id;
2143 new_size = MAX (new_size, old_info->max_domain);
2145 /* make the new size a power of two */
2147 while (new_size > i)
2150 /* this is a bounded memory retention issue: may want to
2151 * handle it differently when we'll have a rcu-like system.
2153 runtime_info = (MonoClassRuntimeInfo *)mono_image_alloc0 (klass->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2154 runtime_info->max_domain = new_size - 1;
2155 /* copy the stuff from the older info */
2157 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2159 runtime_info->domain_vtables [domain->domain_id] = vt;
2161 mono_memory_barrier ();
2162 klass->runtime_info = runtime_info;
2165 if (klass == mono_defaults.runtimetype_class) {
2166 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2167 if (!is_ok (error)) {
2168 mono_domain_unlock (domain);
2169 mono_loader_unlock ();
2173 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2174 /* This is unregistered in
2175 unregister_vtable_reflection_type() in
2177 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2180 mono_domain_unlock (domain);
2181 mono_loader_unlock ();
2183 /* make sure the parent is initialized */
2184 /*FIXME shouldn't this fail the current type?*/
2186 mono_class_vtable_full (domain, klass->parent, error);
2191 #ifndef DISABLE_REMOTING
2193 * mono_class_proxy_vtable:
2194 * @domain: the application domain
2195 * @remove_class: the remote class
2196 * @error: set on error
2198 * Creates a vtable for transparent proxies. It is basically
2199 * a copy of the real vtable of the class wrapped in @remote_class,
2200 * but all function pointers invoke the remoting functions, and
2201 * vtable->klass points to the transparent proxy class, and not to @class.
2203 * On failure returns NULL and sets @error
2206 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type, MonoError *error)
2208 MONO_REQ_GC_UNSAFE_MODE;
2210 MonoVTable *vt, *pvt;
2211 int i, j, vtsize, extra_interface_vtsize = 0;
2212 guint32 max_interface_id;
2214 GSList *extra_interfaces = NULL;
2215 MonoClass *klass = remote_class->proxy_class;
2216 gpointer *interface_offsets;
2217 uint8_t *bitmap = NULL;
2219 size_t imt_table_bytes;
2221 #ifdef COMPRESSED_INTERFACE_BITMAP
2225 mono_error_init (error);
2227 vt = mono_class_vtable (domain, klass);
2228 g_assert (vt); /*FIXME property handle failure*/
2229 max_interface_id = vt->max_interface_id;
2231 /* Calculate vtable space for extra interfaces */
2232 for (j = 0; j < remote_class->interface_count; j++) {
2233 MonoClass* iclass = remote_class->interfaces[j];
2237 /*FIXME test for interfaces with variant generic arguments*/
2238 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, iclass->interface_id))
2239 continue; /* interface implemented by the class */
2240 if (g_slist_find (extra_interfaces, iclass))
2243 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2245 method_count = mono_class_num_methods (iclass);
2247 ifaces = mono_class_get_implemented_interfaces (iclass, error);
2251 for (i = 0; i < ifaces->len; ++i) {
2252 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2253 /*FIXME test for interfaces with variant generic arguments*/
2254 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, ic->interface_id))
2255 continue; /* interface implemented by the class */
2256 if (g_slist_find (extra_interfaces, ic))
2258 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2259 method_count += mono_class_num_methods (ic);
2261 g_ptr_array_free (ifaces, TRUE);
2265 extra_interface_vtsize += method_count * sizeof (gpointer);
2266 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2269 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2270 mono_stats.imt_number_of_tables++;
2271 mono_stats.imt_tables_size += imt_table_bytes;
2273 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer);
2275 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2277 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2278 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2279 g_assert (!((gsize)pvt & 7));
2281 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer));
2283 pvt->klass = mono_defaults.transparent_proxy_class;
2284 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2285 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2287 /* initialize vtable */
2288 mono_class_setup_vtable (klass);
2289 for (i = 0; i < klass->vtable_size; ++i) {
2292 if ((cm = klass->vtable [i])) {
2293 pvt->vtable [i] = create_remoting_trampoline (domain, cm, target_type, error);
2297 pvt->vtable [i] = NULL;
2300 if (mono_class_is_abstract (klass)) {
2301 /* create trampolines for abstract methods */
2302 for (k = klass; k; k = k->parent) {
2304 gpointer iter = NULL;
2305 while ((m = mono_class_get_methods (k, &iter)))
2306 if (!pvt->vtable [m->slot]) {
2307 pvt->vtable [m->slot] = create_remoting_trampoline (domain, m, target_type, error);
2314 pvt->max_interface_id = max_interface_id;
2315 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2316 #ifdef COMPRESSED_INTERFACE_BITMAP
2317 bitmap = (uint8_t *)g_malloc0 (bsize);
2319 bitmap = (uint8_t *)mono_domain_alloc0 (domain, bsize);
2322 for (i = 0; i < klass->interface_offsets_count; ++i) {
2323 int interface_id = klass->interfaces_packed [i]->interface_id;
2324 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2327 if (extra_interfaces) {
2328 int slot = klass->vtable_size;
2334 /* Create trampolines for the methods of the interfaces */
2335 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2336 interf = (MonoClass *)list_item->data;
2338 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2342 while ((cm = mono_class_get_methods (interf, &iter))) {
2343 pvt->vtable [slot + j++] = create_remoting_trampoline (domain, cm, target_type, error);
2348 slot += mono_class_num_methods (interf);
2352 /* Now that the vtable is full, we can actually fill up the IMT */
2353 build_imt (klass, pvt, domain, interface_offsets, extra_interfaces);
2354 if (extra_interfaces) {
2355 g_slist_free (extra_interfaces);
2358 #ifdef COMPRESSED_INTERFACE_BITMAP
2359 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2360 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2361 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2364 pvt->interface_bitmap = bitmap;
2368 if (extra_interfaces)
2369 g_slist_free (extra_interfaces);
2370 #ifdef COMPRESSED_INTERFACE_BITMAP
2376 #endif /* DISABLE_REMOTING */
2379 * mono_class_field_is_special_static:
2381 * Returns whether @field is a thread/context static field.
2384 mono_class_field_is_special_static (MonoClassField *field)
2386 MONO_REQ_GC_NEUTRAL_MODE
2388 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2390 if (mono_field_is_deleted (field))
2392 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2393 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2400 * mono_class_field_get_special_static_type:
2401 * @field: The MonoClassField describing the field.
2403 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2404 * SPECIAL_STATIC_NONE otherwise.
2407 mono_class_field_get_special_static_type (MonoClassField *field)
2409 MONO_REQ_GC_NEUTRAL_MODE
2411 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2412 return SPECIAL_STATIC_NONE;
2413 if (mono_field_is_deleted (field))
2414 return SPECIAL_STATIC_NONE;
2415 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2416 return field_is_special_static (field->parent, field);
2417 return SPECIAL_STATIC_NONE;
2421 * mono_class_has_special_static_fields:
2423 * Returns whenever @klass has any thread/context static fields.
2426 mono_class_has_special_static_fields (MonoClass *klass)
2428 MONO_REQ_GC_NEUTRAL_MODE
2430 MonoClassField *field;
2434 while ((field = mono_class_get_fields (klass, &iter))) {
2435 g_assert (field->parent == klass);
2436 if (mono_class_field_is_special_static (field))
2443 #ifndef DISABLE_REMOTING
2445 * create_remote_class_key:
2446 * Creates an array of pointers that can be used as a hash key for a remote class.
2447 * The first element of the array is the number of pointers.
2450 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2452 MONO_REQ_GC_NEUTRAL_MODE;
2457 if (remote_class == NULL) {
2458 if (mono_class_is_interface (extra_class)) {
2459 key = (void **)g_malloc (sizeof(gpointer) * 3);
2460 key [0] = GINT_TO_POINTER (2);
2461 key [1] = mono_defaults.marshalbyrefobject_class;
2462 key [2] = extra_class;
2464 key = (void **)g_malloc (sizeof(gpointer) * 2);
2465 key [0] = GINT_TO_POINTER (1);
2466 key [1] = extra_class;
2469 if (extra_class != NULL && mono_class_is_interface (extra_class)) {
2470 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2471 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2472 key [1] = remote_class->proxy_class;
2474 // Keep the list of interfaces sorted
2475 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2476 if (extra_class && remote_class->interfaces [i] > extra_class) {
2477 key [j++] = extra_class;
2480 key [j] = remote_class->interfaces [i];
2483 key [j] = extra_class;
2485 // Replace the old class. The interface list is the same
2486 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2487 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2488 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2489 for (i = 0; i < remote_class->interface_count; i++)
2490 key [2 + i] = remote_class->interfaces [i];
2498 * copy_remote_class_key:
2500 * Make a copy of KEY in the domain and return the copy.
2503 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2505 MONO_REQ_GC_NEUTRAL_MODE
2507 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2508 gpointer *mp_key = (gpointer *)mono_domain_alloc (domain, key_size);
2510 memcpy (mp_key, key, key_size);
2516 * mono_remote_class:
2517 * @domain: the application domain
2518 * @class_name: name of the remote class
2519 * @error: set on error
2521 * Creates and initializes a MonoRemoteClass object for a remote type.
2523 * On failure returns NULL and sets @error
2526 mono_remote_class (MonoDomain *domain, MonoStringHandle class_name, MonoClass *proxy_class, MonoError *error)
2528 MONO_REQ_GC_UNSAFE_MODE;
2530 MonoRemoteClass *rc;
2531 gpointer* key, *mp_key;
2534 mono_error_init (error);
2536 key = create_remote_class_key (NULL, proxy_class);
2538 mono_domain_lock (domain);
2539 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2543 mono_domain_unlock (domain);
2547 name = mono_string_to_utf8_mp (domain->mp, MONO_HANDLE_RAW (class_name), error);
2548 if (!is_ok (error)) {
2550 mono_domain_unlock (domain);
2554 mp_key = copy_remote_class_key (domain, key);
2558 if (mono_class_is_interface (proxy_class)) {
2559 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2560 rc->interface_count = 1;
2561 rc->interfaces [0] = proxy_class;
2562 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2564 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2565 rc->interface_count = 0;
2566 rc->proxy_class = proxy_class;
2569 rc->default_vtable = NULL;
2570 rc->xdomain_vtable = NULL;
2571 rc->proxy_class_name = name;
2572 #ifndef DISABLE_PERFCOUNTERS
2573 mono_perfcounters->loader_bytes += mono_string_length (MONO_HANDLE_RAW (class_name)) + 1;
2576 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2578 mono_domain_unlock (domain);
2583 * clone_remote_class:
2584 * Creates a copy of the remote_class, adding the provided class or interface
2586 static MonoRemoteClass*
2587 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2589 MONO_REQ_GC_NEUTRAL_MODE;
2591 MonoRemoteClass *rc;
2592 gpointer* key, *mp_key;
2594 key = create_remote_class_key (remote_class, extra_class);
2595 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2601 mp_key = copy_remote_class_key (domain, key);
2605 if (mono_class_is_interface (extra_class)) {
2607 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2608 rc->proxy_class = remote_class->proxy_class;
2609 rc->interface_count = remote_class->interface_count + 1;
2611 // Keep the list of interfaces sorted, since the hash key of
2612 // the remote class depends on this
2613 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2614 if (remote_class->interfaces [i] > extra_class && i == j)
2615 rc->interfaces [j++] = extra_class;
2616 rc->interfaces [j] = remote_class->interfaces [i];
2619 rc->interfaces [j] = extra_class;
2621 // Replace the old class. The interface array is the same
2622 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2623 rc->proxy_class = extra_class;
2624 rc->interface_count = remote_class->interface_count;
2625 if (rc->interface_count > 0)
2626 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2629 rc->default_vtable = NULL;
2630 rc->xdomain_vtable = NULL;
2631 rc->proxy_class_name = remote_class->proxy_class_name;
2633 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2639 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxyHandle rp, MonoError *error)
2641 MONO_REQ_GC_UNSAFE_MODE;
2643 mono_error_init (error);
2645 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2646 mono_domain_lock (domain);
2647 gint32 target_domain_id = MONO_HANDLE_GETVAL (rp, target_domain_id);
2648 if (target_domain_id != -1) {
2649 if (remote_class->xdomain_vtable == NULL)
2650 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN, error);
2651 mono_domain_unlock (domain);
2652 mono_loader_unlock ();
2653 return_val_if_nok (error, NULL);
2654 return remote_class->xdomain_vtable;
2656 if (remote_class->default_vtable == NULL) {
2657 MonoReflectionTypeHandle reftype = MONO_HANDLE_NEW (MonoReflectionType, NULL);
2658 MONO_HANDLE_GET (reftype, rp, class_to_proxy);
2660 MonoType *type = MONO_HANDLE_GETVAL (reftype, type);
2661 MonoClass *klass = mono_class_from_mono_type (type);
2663 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)))
2664 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP, error);
2667 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN, error);
2668 /* N.B. both branches of the if modify error */
2669 if (!is_ok (error)) {
2670 mono_domain_unlock (domain);
2671 mono_loader_unlock ();
2676 mono_domain_unlock (domain);
2677 mono_loader_unlock ();
2678 return remote_class->default_vtable;
2682 * mono_upgrade_remote_class:
2683 * @domain: the application domain
2684 * @tproxy: the proxy whose remote class has to be upgraded.
2685 * @klass: class to which the remote class can be casted.
2686 * @error: set on error
2688 * Updates the vtable of the remote class by adding the necessary method slots
2689 * and interface offsets so it can be safely casted to klass. klass can be a
2690 * class or an interface. On success returns TRUE, on failure returns FALSE and sets @error.
2693 mono_upgrade_remote_class (MonoDomain *domain, MonoObjectHandle proxy_object, MonoClass *klass, MonoError *error)
2695 MONO_REQ_GC_UNSAFE_MODE;
2697 mono_error_init (error);
2699 MonoTransparentProxyHandle tproxy = MONO_HANDLE_CAST (MonoTransparentProxy, proxy_object);
2700 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (tproxy, remote_class);
2702 gboolean redo_vtable;
2703 if (mono_class_is_interface (klass)) {
2706 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2707 if (remote_class->interfaces [i] == klass)
2708 redo_vtable = FALSE;
2711 redo_vtable = (remote_class->proxy_class != klass);
2714 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2715 mono_domain_lock (domain);
2717 MonoRemoteClass *fresh_remote_class = clone_remote_class (domain, remote_class, klass);
2718 MONO_HANDLE_SETVAL (tproxy, remote_class, MonoRemoteClass*, fresh_remote_class);
2719 MonoRealProxyHandle real_proxy = MONO_HANDLE_NEW (MonoRealProxy, NULL);
2720 MONO_HANDLE_GET (real_proxy, tproxy, rp);
2721 MONO_HANDLE_SETVAL (proxy_object, vtable, MonoVTable*, mono_remote_class_vtable (domain, fresh_remote_class, real_proxy, error));
2727 mono_domain_unlock (domain);
2728 mono_loader_unlock ();
2729 return is_ok (error);
2731 #endif /* DISABLE_REMOTING */
2735 * mono_object_get_virtual_method:
2736 * @obj: object to operate on.
2739 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2740 * the instance of a callvirt of method.
2743 mono_object_get_virtual_method (MonoObject *obj_raw, MonoMethod *method)
2745 MONO_REQ_GC_UNSAFE_MODE;
2746 HANDLE_FUNCTION_ENTER ();
2748 MONO_HANDLE_DCL (MonoObject, obj);
2749 MonoMethod *result = mono_object_handle_get_virtual_method (obj, method, &error);
2750 mono_error_assert_ok (&error);
2751 HANDLE_FUNCTION_RETURN_VAL (result);
2755 * mono_object_get_virtual_method:
2756 * @obj: object to operate on.
2759 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2760 * the instance of a callvirt of method.
2763 mono_object_handle_get_virtual_method (MonoObjectHandle obj, MonoMethod *method, MonoError *error)
2765 mono_error_init (error);
2767 gboolean is_proxy = FALSE;
2768 MonoClass *klass = mono_handle_class (obj);
2769 if (mono_class_is_transparent_proxy (klass)) {
2770 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), remote_class);
2771 klass = remote_class->proxy_class;
2774 return class_get_virtual_method (klass, method, is_proxy, error);
2778 class_get_virtual_method (MonoClass *klass, MonoMethod *method, gboolean is_proxy, MonoError *error)
2780 mono_error_init (error);
2783 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2786 mono_class_setup_vtable (klass);
2787 MonoMethod **vtable = klass->vtable;
2789 if (method->slot == -1) {
2790 /* method->slot might not be set for instances of generic methods */
2791 if (method->is_inflated) {
2792 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2793 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2796 g_assert_not_reached ();
2800 MonoMethod *res = NULL;
2801 /* check method->slot is a valid index: perform isinstance? */
2802 if (method->slot != -1) {
2803 if (mono_class_is_interface (method->klass)) {
2805 gboolean variance_used = FALSE;
2806 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2807 g_assert (iface_offset > 0);
2808 res = vtable [iface_offset + method->slot];
2811 res = vtable [method->slot];
2815 #ifndef DISABLE_REMOTING
2817 /* It may be an interface, abstract class method or generic method */
2818 if (!res || mono_method_signature (res)->generic_param_count)
2821 /* generic methods demand invoke_with_check */
2822 if (mono_method_signature (res)->generic_param_count)
2823 res = mono_marshal_get_remoting_invoke_with_check (res);
2826 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2827 res = mono_cominterop_get_invoke (res);
2830 res = mono_marshal_get_remoting_invoke (res);
2835 if (method->is_inflated) {
2836 /* Have to inflate the result */
2837 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, error);
2845 do_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2847 MONO_REQ_GC_UNSAFE_MODE;
2849 MonoObject *result = NULL;
2851 g_assert (callbacks.runtime_invoke);
2853 mono_error_init (error);
2855 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2856 mono_profiler_method_start_invoke (method);
2858 result = callbacks.runtime_invoke (method, obj, params, exc, error);
2860 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2861 mono_profiler_method_end_invoke (method);
2863 if (!mono_error_ok (error))
2870 * mono_runtime_invoke:
2871 * @method: method to invoke
2872 * @obJ: object instance
2873 * @params: arguments to the method
2874 * @exc: exception information.
2876 * Invokes the method represented by @method on the object @obj.
2878 * obj is the 'this' pointer, it should be NULL for static
2879 * methods, a MonoObject* for object instances and a pointer to
2880 * the value type for value types.
2882 * The params array contains the arguments to the method with the
2883 * same convention: MonoObject* pointers for object instances and
2884 * pointers to the value type otherwise.
2886 * From unmanaged code you'll usually use the
2887 * mono_runtime_invoke() variant.
2889 * Note that this function doesn't handle virtual methods for
2890 * you, it will exec the exact method you pass: we still need to
2891 * expose a function to lookup the derived class implementation
2892 * of a virtual method (there are examples of this in the code,
2895 * You can pass NULL as the exc argument if you don't want to
2896 * catch exceptions, otherwise, *exc will be set to the exception
2897 * thrown, if any. if an exception is thrown, you can't use the
2898 * MonoObject* result from the function.
2900 * If the method returns a value type, it is boxed in an object
2904 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2909 res = mono_runtime_try_invoke (method, obj, params, exc, &error);
2910 if (*exc == NULL && !mono_error_ok(&error)) {
2911 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
2913 mono_error_cleanup (&error);
2915 res = mono_runtime_invoke_checked (method, obj, params, &error);
2916 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
2922 * mono_runtime_try_invoke:
2923 * @method: method to invoke
2924 * @obJ: object instance
2925 * @params: arguments to the method
2926 * @exc: exception information.
2927 * @error: set on error
2929 * Invokes the method represented by @method on the object @obj.
2931 * obj is the 'this' pointer, it should be NULL for static
2932 * methods, a MonoObject* for object instances and a pointer to
2933 * the value type for value types.
2935 * The params array contains the arguments to the method with the
2936 * same convention: MonoObject* pointers for object instances and
2937 * pointers to the value type otherwise.
2939 * From unmanaged code you'll usually use the
2940 * mono_runtime_invoke() variant.
2942 * Note that this function doesn't handle virtual methods for
2943 * you, it will exec the exact method you pass: we still need to
2944 * expose a function to lookup the derived class implementation
2945 * of a virtual method (there are examples of this in the code,
2948 * For this function, you must not pass NULL as the exc argument if
2949 * you don't want to catch exceptions, use
2950 * mono_runtime_invoke_checked(). If an exception is thrown, you
2951 * can't use the MonoObject* result from the function.
2953 * If this method cannot be invoked, @error will be set and @exc and
2954 * the return value must not be used.
2956 * If the method returns a value type, it is boxed in an object
2960 mono_runtime_try_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError* error)
2962 MONO_REQ_GC_UNSAFE_MODE;
2964 g_assert (exc != NULL);
2966 if (mono_runtime_get_no_exec ())
2967 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2969 return do_runtime_invoke (method, obj, params, exc, error);
2973 * mono_runtime_invoke_checked:
2974 * @method: method to invoke
2975 * @obJ: object instance
2976 * @params: arguments to the method
2977 * @error: set on error
2979 * Invokes the method represented by @method on the object @obj.
2981 * obj is the 'this' pointer, it should be NULL for static
2982 * methods, a MonoObject* for object instances and a pointer to
2983 * the value type for value types.
2985 * The params array contains the arguments to the method with the
2986 * same convention: MonoObject* pointers for object instances and
2987 * pointers to the value type otherwise.
2989 * From unmanaged code you'll usually use the
2990 * mono_runtime_invoke() variant.
2992 * Note that this function doesn't handle virtual methods for
2993 * you, it will exec the exact method you pass: we still need to
2994 * expose a function to lookup the derived class implementation
2995 * of a virtual method (there are examples of this in the code,
2998 * If an exception is thrown, you can't use the MonoObject* result
2999 * from the function.
3001 * If this method cannot be invoked, @error will be set. If the
3002 * method throws an exception (and we're in coop mode) the exception
3003 * will be set in @error.
3005 * If the method returns a value type, it is boxed in an object
3009 mono_runtime_invoke_checked (MonoMethod *method, void *obj, void **params, MonoError* error)
3011 MONO_REQ_GC_UNSAFE_MODE;
3013 if (mono_runtime_get_no_exec ())
3014 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
3016 return do_runtime_invoke (method, obj, params, NULL, error);
3020 * mono_method_get_unmanaged_thunk:
3021 * @method: method to generate a thunk for.
3023 * Returns an unmanaged->managed thunk that can be used to call
3024 * a managed method directly from C.
3026 * The thunk's C signature closely matches the managed signature:
3028 * C#: public bool Equals (object obj);
3029 * C: typedef MonoBoolean (*Equals)(MonoObject*,
3030 * MonoObject*, MonoException**);
3032 * The 1st ("this") parameter must not be used with static methods:
3034 * C#: public static bool ReferenceEquals (object a, object b);
3035 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
3038 * The last argument must be a non-null pointer of a MonoException* pointer.
3039 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
3040 * exception has been thrown in managed code. Otherwise it will point
3041 * to the MonoException* caught by the thunk. In this case, the result of
3042 * the thunk is undefined:
3044 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
3045 * MonoException *ex = NULL;
3046 * Equals func = mono_method_get_unmanaged_thunk (method);
3047 * MonoBoolean res = func (thisObj, objToCompare, &ex);
3049 * // handle exception
3052 * The calling convention of the thunk matches the platform's default
3053 * convention. This means that under Windows, C declarations must
3054 * contain the __stdcall attribute:
3056 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
3057 * MonoObject*, MonoException**);
3061 * Value type arguments and return values are treated as they were objects:
3063 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
3064 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
3066 * Arguments must be properly boxed upon trunk's invocation, while return
3067 * values must be unboxed.
3070 mono_method_get_unmanaged_thunk (MonoMethod *method)
3072 MONO_REQ_GC_NEUTRAL_MODE;
3073 MONO_REQ_API_ENTRYPOINT;
3078 g_assert (!mono_threads_is_coop_enabled ());
3080 MONO_ENTER_GC_UNSAFE;
3081 method = mono_marshal_get_thunk_invoke_wrapper (method);
3082 res = mono_compile_method_checked (method, &error);
3083 mono_error_cleanup (&error);
3084 MONO_EXIT_GC_UNSAFE;
3090 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
3092 MONO_REQ_GC_UNSAFE_MODE;
3096 /* object fields cannot be byref, so we don't need a
3098 gpointer *p = (gpointer*)dest;
3105 case MONO_TYPE_BOOLEAN:
3107 case MONO_TYPE_U1: {
3108 guint8 *p = (guint8*)dest;
3109 *p = value ? *(guint8*)value : 0;
3114 case MONO_TYPE_CHAR: {
3115 guint16 *p = (guint16*)dest;
3116 *p = value ? *(guint16*)value : 0;
3119 #if SIZEOF_VOID_P == 4
3124 case MONO_TYPE_U4: {
3125 gint32 *p = (gint32*)dest;
3126 *p = value ? *(gint32*)value : 0;
3129 #if SIZEOF_VOID_P == 8
3134 case MONO_TYPE_U8: {
3135 gint64 *p = (gint64*)dest;
3136 *p = value ? *(gint64*)value : 0;
3139 case MONO_TYPE_R4: {
3140 float *p = (float*)dest;
3141 *p = value ? *(float*)value : 0;
3144 case MONO_TYPE_R8: {
3145 double *p = (double*)dest;
3146 *p = value ? *(double*)value : 0;
3149 case MONO_TYPE_STRING:
3150 case MONO_TYPE_SZARRAY:
3151 case MONO_TYPE_CLASS:
3152 case MONO_TYPE_OBJECT:
3153 case MONO_TYPE_ARRAY:
3154 mono_gc_wbarrier_generic_store (dest, deref_pointer ? *(MonoObject **)value : (MonoObject *)value);
3156 case MONO_TYPE_FNPTR:
3157 case MONO_TYPE_PTR: {
3158 gpointer *p = (gpointer*)dest;
3159 *p = deref_pointer? *(gpointer*)value: value;
3162 case MONO_TYPE_VALUETYPE:
3163 /* note that 't' and 'type->type' can be different */
3164 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3165 t = mono_class_enum_basetype (type->data.klass)->type;
3168 MonoClass *klass = mono_class_from_mono_type (type);
3169 int size = mono_class_value_size (klass, NULL);
3171 mono_gc_bzero_atomic (dest, size);
3173 mono_gc_wbarrier_value_copy (dest, value, 1, klass);
3176 case MONO_TYPE_GENERICINST:
3177 t = type->data.generic_class->container_class->byval_arg.type;
3180 g_error ("got type %x", type->type);
3185 * mono_field_set_value:
3186 * @obj: Instance object
3187 * @field: MonoClassField describing the field to set
3188 * @value: The value to be set
3190 * Sets the value of the field described by @field in the object instance @obj
3191 * to the value passed in @value. This method should only be used for instance
3192 * fields. For static fields, use mono_field_static_set_value.
3194 * The value must be on the native format of the field type.
3197 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3199 MONO_REQ_GC_UNSAFE_MODE;
3203 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3205 dest = (char*)obj + field->offset;
3206 mono_copy_value (field->type, dest, value, FALSE);
3210 * mono_field_static_set_value:
3211 * @field: MonoClassField describing the field to set
3212 * @value: The value to be set
3214 * Sets the value of the static field described by @field
3215 * to the value passed in @value.
3217 * The value must be on the native format of the field type.
3220 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3222 MONO_REQ_GC_UNSAFE_MODE;
3226 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3227 /* you cant set a constant! */
3228 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3230 if (field->offset == -1) {
3231 /* Special static */
3234 mono_domain_lock (vt->domain);
3235 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3236 mono_domain_unlock (vt->domain);
3237 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3239 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3241 mono_copy_value (field->type, dest, value, FALSE);
3245 * mono_vtable_get_static_field_data:
3247 * Internal use function: return a pointer to the memory holding the static fields
3248 * for a class or NULL if there are no static fields.
3249 * This is exported only for use by the debugger.
3252 mono_vtable_get_static_field_data (MonoVTable *vt)
3254 MONO_REQ_GC_NEUTRAL_MODE
3256 if (!vt->has_static_fields)
3258 return vt->vtable [vt->klass->vtable_size];
3262 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3264 MONO_REQ_GC_UNSAFE_MODE;
3268 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3269 if (field->offset == -1) {
3270 /* Special static */
3273 mono_domain_lock (vt->domain);
3274 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3275 mono_domain_unlock (vt->domain);
3276 src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3278 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3281 src = (guint8*)obj + field->offset;
3288 * mono_field_get_value:
3289 * @obj: Object instance
3290 * @field: MonoClassField describing the field to fetch information from
3291 * @value: pointer to the location where the value will be stored
3293 * Use this routine to get the value of the field @field in the object
3296 * The pointer provided by value must be of the field type, for reference
3297 * types this is a MonoObject*, for value types its the actual pointer to
3302 * mono_field_get_value (obj, int_field, &i);
3305 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3307 MONO_REQ_GC_UNSAFE_MODE;
3313 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3315 src = (char*)obj + field->offset;
3316 mono_copy_value (field->type, value, src, TRUE);
3320 * mono_field_get_value_object:
3321 * @domain: domain where the object will be created (if boxing)
3322 * @field: MonoClassField describing the field to fetch information from
3323 * @obj: The object instance for the field.
3325 * Returns: a new MonoObject with the value from the given field. If the
3326 * field represents a value type, the value is boxed.
3330 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3333 MonoObject* result = mono_field_get_value_object_checked (domain, field, obj, &error);
3334 mono_error_assert_ok (&error);
3339 * mono_field_get_value_object_checked:
3340 * @domain: domain where the object will be created (if boxing)
3341 * @field: MonoClassField describing the field to fetch information from
3342 * @obj: The object instance for the field.
3343 * @error: Set on error.
3345 * Returns: a new MonoObject with the value from the given field. If the
3346 * field represents a value type, the value is boxed. On error returns NULL and sets @error.
3350 mono_field_get_value_object_checked (MonoDomain *domain, MonoClassField *field, MonoObject *obj, MonoError *error)
3352 MONO_REQ_GC_UNSAFE_MODE;
3354 mono_error_init (error);
3358 MonoVTable *vtable = NULL;
3360 gboolean is_static = FALSE;
3361 gboolean is_ref = FALSE;
3362 gboolean is_literal = FALSE;
3363 gboolean is_ptr = FALSE;
3364 MonoType *type = mono_field_get_type_checked (field, error);
3366 return_val_if_nok (error, NULL);
3368 switch (type->type) {
3369 case MONO_TYPE_STRING:
3370 case MONO_TYPE_OBJECT:
3371 case MONO_TYPE_CLASS:
3372 case MONO_TYPE_ARRAY:
3373 case MONO_TYPE_SZARRAY:
3378 case MONO_TYPE_BOOLEAN:
3381 case MONO_TYPE_CHAR:
3390 case MONO_TYPE_VALUETYPE:
3391 is_ref = type->byref;
3393 case MONO_TYPE_GENERICINST:
3394 is_ref = !mono_type_generic_inst_is_valuetype (type);
3400 g_error ("type 0x%x not handled in "
3401 "mono_field_get_value_object", type->type);
3405 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3408 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3412 vtable = mono_class_vtable_full (domain, field->parent, error);
3413 return_val_if_nok (error, NULL);
3415 if (!vtable->initialized) {
3416 mono_runtime_class_init_full (vtable, error);
3417 return_val_if_nok (error, NULL);
3426 get_default_field_value (domain, field, &o, error);
3427 return_val_if_nok (error, NULL);
3428 } else if (is_static) {
3429 mono_field_static_get_value_checked (vtable, field, &o, error);
3430 return_val_if_nok (error, NULL);
3432 mono_field_get_value (obj, field, &o);
3438 static MonoMethod *m;
3444 MonoClass *ptr_klass = mono_class_get_pointer_class ();
3445 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3451 get_default_field_value (domain, field, v, error);
3452 return_val_if_nok (error, NULL);
3453 } else if (is_static) {
3454 mono_field_static_get_value_checked (vtable, field, v, error);
3455 return_val_if_nok (error, NULL);
3457 mono_field_get_value (obj, field, v);
3460 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3461 args [0] = ptr ? *ptr : NULL;
3462 args [1] = mono_type_get_object_checked (mono_domain_get (), type, error);
3463 return_val_if_nok (error, NULL);
3465 o = mono_runtime_invoke_checked (m, NULL, args, error);
3466 return_val_if_nok (error, NULL);
3471 /* boxed value type */
3472 klass = mono_class_from_mono_type (type);
3474 if (mono_class_is_nullable (klass))
3475 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass, error);
3477 o = mono_object_new_checked (domain, klass, error);
3478 return_val_if_nok (error, NULL);
3479 v = ((gchar *) o) + sizeof (MonoObject);
3482 get_default_field_value (domain, field, v, error);
3483 return_val_if_nok (error, NULL);
3484 } else if (is_static) {
3485 mono_field_static_get_value_checked (vtable, field, v, error);
3486 return_val_if_nok (error, NULL);
3488 mono_field_get_value (obj, field, v);
3495 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value, MonoError *error)
3497 MONO_REQ_GC_UNSAFE_MODE;
3499 mono_error_init (error);
3501 const char *p = blob;
3502 mono_metadata_decode_blob_size (p, &p);
3505 case MONO_TYPE_BOOLEAN:
3508 *(guint8 *) value = *p;
3510 case MONO_TYPE_CHAR:
3513 *(guint16*) value = read16 (p);
3517 *(guint32*) value = read32 (p);
3521 *(guint64*) value = read64 (p);
3524 readr4 (p, (float*) value);
3527 readr8 (p, (double*) value);
3529 case MONO_TYPE_STRING:
3530 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob, error);
3532 case MONO_TYPE_CLASS:
3533 *(gpointer*) value = NULL;
3537 g_warning ("type 0x%02x should not be in constant table", type);
3543 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error)
3545 MONO_REQ_GC_NEUTRAL_MODE;
3547 MonoTypeEnum def_type;
3550 mono_error_init (error);
3552 data = mono_class_get_field_default_value (field, &def_type);
3553 mono_get_constant_value_from_blob (domain, def_type, data, value, error);
3557 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3559 MONO_REQ_GC_UNSAFE_MODE;
3563 mono_error_init (error);
3565 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3567 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3568 get_default_field_value (vt->domain, field, value, error);
3572 if (field->offset == -1) {
3573 /* Special static */
3574 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3575 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3577 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3579 mono_copy_value (field->type, value, src, TRUE);
3583 * mono_field_static_get_value:
3584 * @vt: vtable to the object
3585 * @field: MonoClassField describing the field to fetch information from
3586 * @value: where the value is returned
3588 * Use this routine to get the value of the static field @field value.
3590 * The pointer provided by value must be of the field type, for reference
3591 * types this is a MonoObject*, for value types its the actual pointer to
3596 * mono_field_static_get_value (vt, int_field, &i);
3599 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3601 MONO_REQ_GC_NEUTRAL_MODE;
3604 mono_field_static_get_value_checked (vt, field, value, &error);
3605 mono_error_cleanup (&error);
3609 * mono_field_static_get_value_checked:
3610 * @vt: vtable to the object
3611 * @field: MonoClassField describing the field to fetch information from
3612 * @value: where the value is returned
3613 * @error: set on error
3615 * Use this routine to get the value of the static field @field value.
3617 * The pointer provided by value must be of the field type, for reference
3618 * types this is a MonoObject*, for value types its the actual pointer to
3623 * mono_field_static_get_value_checked (vt, int_field, &i, error);
3624 * if (!is_ok (error)) { ... }
3626 * On failure sets @error.
3629 mono_field_static_get_value_checked (MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3631 MONO_REQ_GC_NEUTRAL_MODE;
3633 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value, error);
3637 * mono_property_set_value:
3638 * @prop: MonoProperty to set
3639 * @obj: instance object on which to act
3640 * @params: parameters to pass to the propery
3641 * @exc: optional exception
3643 * Invokes the property's set method with the given arguments on the
3644 * object instance obj (or NULL for static properties).
3646 * You can pass NULL as the exc argument if you don't want to
3647 * catch exceptions, otherwise, *exc will be set to the exception
3648 * thrown, if any. if an exception is thrown, you can't use the
3649 * MonoObject* result from the function.
3652 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3654 MONO_REQ_GC_UNSAFE_MODE;
3657 do_runtime_invoke (prop->set, obj, params, exc, &error);
3658 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3659 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3661 mono_error_cleanup (&error);
3666 * mono_property_set_value_checked:
3667 * @prop: MonoProperty to set
3668 * @obj: instance object on which to act
3669 * @params: parameters to pass to the propery
3670 * @error: set on error
3672 * Invokes the property's set method with the given arguments on the
3673 * object instance obj (or NULL for static properties).
3675 * Returns: TRUE on success. On failure returns FALSE and sets @error.
3676 * If an exception is thrown, it will be caught and returned via @error.
3679 mono_property_set_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3681 MONO_REQ_GC_UNSAFE_MODE;
3685 mono_error_init (error);
3686 do_runtime_invoke (prop->set, obj, params, &exc, error);
3687 if (exc != NULL && is_ok (error))
3688 mono_error_set_exception_instance (error, (MonoException*)exc);
3689 return is_ok (error);
3693 * mono_property_get_value:
3694 * @prop: MonoProperty to fetch
3695 * @obj: instance object on which to act
3696 * @params: parameters to pass to the propery
3697 * @exc: optional exception
3699 * Invokes the property's get method with the given arguments on the
3700 * object instance obj (or NULL for static properties).
3702 * You can pass NULL as the exc argument if you don't want to
3703 * catch exceptions, otherwise, *exc will be set to the exception
3704 * thrown, if any. if an exception is thrown, you can't use the
3705 * MonoObject* result from the function.
3707 * Returns: the value from invoking the get method on the property.
3710 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3712 MONO_REQ_GC_UNSAFE_MODE;
3715 MonoObject *val = do_runtime_invoke (prop->get, obj, params, exc, &error);
3716 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3717 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3719 mono_error_cleanup (&error); /* FIXME don't raise here */
3726 * mono_property_get_value_checked:
3727 * @prop: MonoProperty to fetch
3728 * @obj: instance object on which to act
3729 * @params: parameters to pass to the propery
3730 * @error: set on error
3732 * Invokes the property's get method with the given arguments on the
3733 * object instance obj (or NULL for static properties).
3735 * If an exception is thrown, you can't use the
3736 * MonoObject* result from the function. The exception will be propagated via @error.
3738 * Returns: the value from invoking the get method on the property. On
3739 * failure returns NULL and sets @error.
3742 mono_property_get_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3744 MONO_REQ_GC_UNSAFE_MODE;
3747 MonoObject *val = do_runtime_invoke (prop->get, obj, params, &exc, error);
3748 if (exc != NULL && !is_ok (error))
3749 mono_error_set_exception_instance (error, (MonoException*) exc);
3757 * mono_nullable_init:
3758 * @buf: The nullable structure to initialize.
3759 * @value: the value to initialize from
3760 * @klass: the type for the object
3762 * Initialize the nullable structure pointed to by @buf from @value which
3763 * should be a boxed value type. The size of @buf should be able to hold
3764 * as much data as the @klass->instance_size (which is the number of bytes
3765 * that will be copies).
3767 * Since Nullables have variable structure, we can not define a C
3768 * structure for them.
3771 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3773 MONO_REQ_GC_UNSAFE_MODE;
3775 MonoClass *param_class = klass->cast_class;
3777 mono_class_setup_fields (klass);
3778 g_assert (klass->fields_inited);
3780 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3781 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3783 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3785 if (param_class->has_references)
3786 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3788 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3790 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3795 * mono_nullable_box:
3796 * @buf: The buffer representing the data to be boxed
3797 * @klass: the type to box it as.
3798 * @error: set on oerr
3800 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3801 * @buf. On failure returns NULL and sets @error
3804 mono_nullable_box (guint8 *buf, MonoClass *klass, MonoError *error)
3806 MONO_REQ_GC_UNSAFE_MODE;
3808 mono_error_init (error);
3809 MonoClass *param_class = klass->cast_class;
3811 mono_class_setup_fields (klass);
3812 g_assert (klass->fields_inited);
3814 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3815 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3817 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3818 MonoObject *o = mono_object_new_checked (mono_domain_get (), param_class, error);
3819 return_val_if_nok (error, NULL);
3820 if (param_class->has_references)
3821 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3823 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3831 * mono_get_delegate_invoke:
3832 * @klass: The delegate class
3834 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3837 mono_get_delegate_invoke (MonoClass *klass)
3839 MONO_REQ_GC_NEUTRAL_MODE;
3843 /* This is called at runtime, so avoid the slower search in metadata */
3844 mono_class_setup_methods (klass);
3845 if (mono_class_has_failure (klass))
3847 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3852 * mono_get_delegate_begin_invoke:
3853 * @klass: The delegate class
3855 * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3858 mono_get_delegate_begin_invoke (MonoClass *klass)
3860 MONO_REQ_GC_NEUTRAL_MODE;
3864 /* This is called at runtime, so avoid the slower search in metadata */
3865 mono_class_setup_methods (klass);
3866 if (mono_class_has_failure (klass))
3868 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3873 * mono_get_delegate_end_invoke:
3874 * @klass: The delegate class
3876 * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3879 mono_get_delegate_end_invoke (MonoClass *klass)
3881 MONO_REQ_GC_NEUTRAL_MODE;
3885 /* This is called at runtime, so avoid the slower search in metadata */
3886 mono_class_setup_methods (klass);
3887 if (mono_class_has_failure (klass))
3889 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3894 * mono_runtime_delegate_invoke:
3895 * @delegate: pointer to a delegate object.
3896 * @params: parameters for the delegate.
3897 * @exc: Pointer to the exception result.
3899 * Invokes the delegate method @delegate with the parameters provided.
3901 * You can pass NULL as the exc argument if you don't want to
3902 * catch exceptions, otherwise, *exc will be set to the exception
3903 * thrown, if any. if an exception is thrown, you can't use the
3904 * MonoObject* result from the function.
3907 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3909 MONO_REQ_GC_UNSAFE_MODE;
3913 MonoObject *result = mono_runtime_delegate_try_invoke (delegate, params, exc, &error);
3915 mono_error_cleanup (&error);
3918 if (!is_ok (&error))
3919 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
3923 MonoObject *result = mono_runtime_delegate_invoke_checked (delegate, params, &error);
3924 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
3930 * mono_runtime_delegate_try_invoke:
3931 * @delegate: pointer to a delegate object.
3932 * @params: parameters for the delegate.
3933 * @exc: Pointer to the exception result.
3934 * @error: set on error
3936 * Invokes the delegate method @delegate with the parameters provided.
3938 * You can pass NULL as the exc argument if you don't want to
3939 * catch exceptions, otherwise, *exc will be set to the exception
3940 * thrown, if any. On failure to execute, @error will be set.
3941 * if an exception is thrown, you can't use the
3942 * MonoObject* result from the function.
3945 mono_runtime_delegate_try_invoke (MonoObject *delegate, void **params, MonoObject **exc, MonoError *error)
3947 MONO_REQ_GC_UNSAFE_MODE;
3949 mono_error_init (error);
3951 MonoClass *klass = delegate->vtable->klass;
3954 im = mono_get_delegate_invoke (klass);
3956 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3959 o = mono_runtime_try_invoke (im, delegate, params, exc, error);
3961 o = mono_runtime_invoke_checked (im, delegate, params, error);
3968 * mono_runtime_delegate_invoke_checked:
3969 * @delegate: pointer to a delegate object.
3970 * @params: parameters for the delegate.
3971 * @error: set on error
3973 * Invokes the delegate method @delegate with the parameters provided.
3975 * On failure @error will be set and you can't use the MonoObject*
3976 * result from the function.
3979 mono_runtime_delegate_invoke_checked (MonoObject *delegate, void **params, MonoError *error)
3981 mono_error_init (error);
3982 return mono_runtime_delegate_try_invoke (delegate, params, NULL, error);
3985 static char **main_args = NULL;
3986 static int num_main_args = 0;
3989 * mono_runtime_get_main_args:
3991 * Returns: a MonoArray with the arguments passed to the main program
3994 mono_runtime_get_main_args (void)
3996 MONO_REQ_GC_UNSAFE_MODE;
3998 MonoArray *result = mono_runtime_get_main_args_checked (&error);
3999 mono_error_assert_ok (&error);
4004 * mono_runtime_get_main_args:
4005 * @error: set on error
4007 * Returns: a MonoArray with the arguments passed to the main
4008 * program. On failure returns NULL and sets @error.
4011 mono_runtime_get_main_args_checked (MonoError *error)
4015 MonoDomain *domain = mono_domain_get ();
4017 mono_error_init (error);
4019 res = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, num_main_args, error);
4020 return_val_if_nok (error, NULL);
4022 for (i = 0; i < num_main_args; ++i)
4023 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
4029 free_main_args (void)
4031 MONO_REQ_GC_NEUTRAL_MODE;
4035 for (i = 0; i < num_main_args; ++i)
4036 g_free (main_args [i]);
4043 * mono_runtime_set_main_args:
4044 * @argc: number of arguments from the command line
4045 * @argv: array of strings from the command line
4047 * Set the command line arguments from an embedding application that doesn't otherwise call
4048 * mono_runtime_run_main ().
4051 mono_runtime_set_main_args (int argc, char* argv[])
4053 MONO_REQ_GC_NEUTRAL_MODE;
4058 main_args = g_new0 (char*, argc);
4059 num_main_args = argc;
4061 for (i = 0; i < argc; ++i) {
4064 utf8_arg = mono_utf8_from_external (argv[i]);
4065 if (utf8_arg == NULL) {
4066 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
4067 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4071 main_args [i] = utf8_arg;
4078 * Prepare an array of arguments in order to execute a standard Main()
4079 * method (argc/argv contains the executable name). This method also
4080 * sets the command line argument value needed by System.Environment.
4084 prepare_run_main (MonoMethod *method, int argc, char *argv[])
4086 MONO_REQ_GC_UNSAFE_MODE;
4090 MonoArray *args = NULL;
4091 MonoDomain *domain = mono_domain_get ();
4092 gchar *utf8_fullpath;
4093 MonoMethodSignature *sig;
4095 g_assert (method != NULL);
4097 mono_thread_set_main (mono_thread_current ());
4099 main_args = g_new0 (char*, argc);
4100 num_main_args = argc;
4102 if (!g_path_is_absolute (argv [0])) {
4103 gchar *basename = g_path_get_basename (argv [0]);
4104 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
4108 utf8_fullpath = mono_utf8_from_external (fullpath);
4109 if(utf8_fullpath == NULL) {
4110 /* Printing the arg text will cause glib to
4111 * whinge about "Invalid UTF-8", but at least
4112 * its relevant, and shows the problem text
4115 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
4116 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4123 utf8_fullpath = mono_utf8_from_external (argv[0]);
4124 if(utf8_fullpath == NULL) {
4125 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
4126 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4131 main_args [0] = utf8_fullpath;
4133 for (i = 1; i < argc; ++i) {
4136 utf8_arg=mono_utf8_from_external (argv[i]);
4137 if(utf8_arg==NULL) {
4138 /* Ditto the comment about Invalid UTF-8 here */
4139 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
4140 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4144 main_args [i] = utf8_arg;
4149 sig = mono_method_signature (method);
4151 g_print ("Unable to load Main method.\n");
4155 if (sig->param_count) {
4156 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, argc, &error);
4157 mono_error_assert_ok (&error);
4158 for (i = 0; i < argc; ++i) {
4159 /* The encodings should all work, given that
4160 * we've checked all these args for the
4163 gchar *str = mono_utf8_from_external (argv [i]);
4164 MonoString *arg = mono_string_new (domain, str);
4165 mono_array_setref (args, i, arg);
4169 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, 0, &error);
4170 mono_error_assert_ok (&error);
4173 mono_assembly_set_main (method->klass->image->assembly);
4179 * mono_runtime_run_main:
4180 * @method: the method to start the application with (usually Main)
4181 * @argc: number of arguments from the command line
4182 * @argv: array of strings from the command line
4183 * @exc: excetption results
4185 * Execute a standard Main() method (argc/argv contains the
4186 * executable name). This method also sets the command line argument value
4187 * needed by System.Environment.
4192 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
4195 MONO_REQ_GC_UNSAFE_MODE;
4198 MonoArray *args = prepare_run_main (method, argc, argv);
4201 res = mono_runtime_try_exec_main (method, args, exc);
4203 res = mono_runtime_exec_main_checked (method, args, &error);
4204 mono_error_raise_exception (&error); /* OK to throw, external only without a better alternative */
4210 * mono_runtime_run_main_checked:
4211 * @method: the method to start the application with (usually Main)
4212 * @argc: number of arguments from the command line
4213 * @argv: array of strings from the command line
4214 * @error: set on error
4216 * Execute a standard Main() method (argc/argv contains the
4217 * executable name). This method also sets the command line argument value
4218 * needed by System.Environment. On failure sets @error.
4223 mono_runtime_run_main_checked (MonoMethod *method, int argc, char* argv[],
4226 mono_error_init (error);
4227 MonoArray *args = prepare_run_main (method, argc, argv);
4228 return mono_runtime_exec_main_checked (method, args, error);
4232 * mono_runtime_try_run_main:
4233 * @method: the method to start the application with (usually Main)
4234 * @argc: number of arguments from the command line
4235 * @argv: array of strings from the command line
4236 * @exc: set if Main throws an exception
4237 * @error: set if Main can't be executed
4239 * Execute a standard Main() method (argc/argv contains the executable
4240 * name). This method also sets the command line argument value needed
4241 * by System.Environment. On failure sets @error if Main can't be
4242 * executed or @exc if it threw and exception.
4247 mono_runtime_try_run_main (MonoMethod *method, int argc, char* argv[],
4251 MonoArray *args = prepare_run_main (method, argc, argv);
4252 return mono_runtime_try_exec_main (method, args, exc);
4257 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4259 static MonoMethod *serialize_method;
4265 if (!serialize_method) {
4266 MonoClass *klass = mono_class_get_remoting_services_class ();
4267 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
4270 if (!serialize_method) {
4275 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
4280 array = mono_runtime_try_invoke (serialize_method, NULL, params, exc, &error);
4281 if (*exc == NULL && !mono_error_ok (&error))
4282 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert serialize_object to MonoError */
4284 mono_error_cleanup (&error);
4293 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4295 MONO_REQ_GC_UNSAFE_MODE;
4297 static MonoMethod *deserialize_method;
4303 if (!deserialize_method) {
4304 MonoClass *klass = mono_class_get_remoting_services_class ();
4305 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
4307 if (!deserialize_method) {
4315 result = mono_runtime_try_invoke (deserialize_method, NULL, params, exc, &error);
4316 if (*exc == NULL && !mono_error_ok (&error))
4317 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert deserialize_object to MonoError */
4319 mono_error_cleanup (&error);
4327 #ifndef DISABLE_REMOTING
4329 make_transparent_proxy (MonoObject *obj, MonoError *error)
4331 MONO_REQ_GC_UNSAFE_MODE;
4333 static MonoMethod *get_proxy_method;
4335 MonoDomain *domain = mono_domain_get ();
4336 MonoRealProxy *real_proxy;
4337 MonoReflectionType *reflection_type;
4338 MonoTransparentProxy *transparent_proxy;
4340 mono_error_init (error);
4342 if (!get_proxy_method)
4343 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
4345 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
4347 real_proxy = (MonoRealProxy*) mono_object_new_checked (domain, mono_defaults.real_proxy_class, error);
4348 return_val_if_nok (error, NULL);
4349 reflection_type = mono_type_get_object_checked (domain, &obj->vtable->klass->byval_arg, error);
4350 return_val_if_nok (error, NULL);
4352 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
4353 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
4355 MonoObject *exc = NULL;
4357 transparent_proxy = (MonoTransparentProxy*) mono_runtime_try_invoke (get_proxy_method, real_proxy, NULL, &exc, error);
4358 if (exc != NULL && is_ok (error))
4359 mono_error_set_exception_instance (error, (MonoException*)exc);
4361 return (MonoObject*) transparent_proxy;
4363 #endif /* DISABLE_REMOTING */
4366 * mono_object_xdomain_representation
4368 * @target_domain: a domain
4369 * @error: set on error.
4371 * Creates a representation of obj in the domain target_domain. This
4372 * is either a copy of obj arrived through via serialization and
4373 * deserialization or a proxy, depending on whether the object is
4374 * serializable or marshal by ref. obj must not be in target_domain.
4376 * If the object cannot be represented in target_domain, NULL is
4377 * returned and @error is set appropriately.
4380 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoError *error)
4382 MONO_REQ_GC_UNSAFE_MODE;
4384 mono_error_init (error);
4385 MonoObject *deserialized = NULL;
4387 #ifndef DISABLE_REMOTING
4388 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
4389 deserialized = make_transparent_proxy (obj, error);
4394 gboolean failure = FALSE;
4395 MonoDomain *domain = mono_domain_get ();
4396 MonoObject *serialized;
4397 MonoObject *exc = NULL;
4399 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
4400 serialized = serialize_object (obj, &failure, &exc);
4401 mono_domain_set_internal_with_options (target_domain, FALSE);
4403 deserialized = deserialize_object (serialized, &failure, &exc);
4404 if (domain != target_domain)
4405 mono_domain_set_internal_with_options (domain, FALSE);
4407 mono_error_set_exception_instance (error, (MonoException*)exc);
4410 return deserialized;
4413 /* Used in call_unhandled_exception_delegate */
4415 create_unhandled_exception_eventargs (MonoObject *exc, MonoError *error)
4417 MONO_REQ_GC_UNSAFE_MODE;
4419 mono_error_init (error);
4422 MonoMethod *method = NULL;
4423 MonoBoolean is_terminating = TRUE;
4426 klass = mono_class_get_unhandled_exception_event_args_class ();
4427 mono_class_init (klass);
4429 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4430 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
4434 args [1] = &is_terminating;
4436 obj = mono_object_new_checked (mono_domain_get (), klass, error);
4437 return_val_if_nok (error, NULL);
4439 mono_runtime_invoke_checked (method, obj, args, error);
4440 return_val_if_nok (error, NULL);
4445 /* Used in mono_unhandled_exception */
4447 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4448 MONO_REQ_GC_UNSAFE_MODE;
4451 MonoObject *e = NULL;
4453 MonoDomain *current_domain = mono_domain_get ();
4455 if (domain != current_domain)
4456 mono_domain_set_internal_with_options (domain, FALSE);
4458 g_assert (domain == mono_object_domain (domain->domain));
4460 if (mono_object_domain (exc) != domain) {
4462 exc = mono_object_xdomain_representation (exc, domain, &error);
4464 if (!is_ok (&error)) {
4465 MonoError inner_error;
4466 MonoException *serialization_exc = mono_error_convert_to_exception (&error);
4467 exc = mono_object_xdomain_representation ((MonoObject*)serialization_exc, domain, &inner_error);
4468 mono_error_assert_ok (&inner_error);
4470 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4471 "System.Runtime.Serialization", "SerializationException",
4472 "Could not serialize unhandled exception.");
4476 g_assert (mono_object_domain (exc) == domain);
4478 pa [0] = domain->domain;
4479 pa [1] = create_unhandled_exception_eventargs (exc, &error);
4480 mono_error_assert_ok (&error);
4481 mono_runtime_delegate_try_invoke (delegate, pa, &e, &error);
4482 if (!is_ok (&error)) {
4484 e = (MonoObject*)mono_error_convert_to_exception (&error);
4486 mono_error_cleanup (&error);
4489 if (domain != current_domain)
4490 mono_domain_set_internal_with_options (current_domain, FALSE);
4493 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4494 if (!mono_error_ok (&error)) {
4495 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4496 mono_error_cleanup (&error);
4498 g_warning ("exception inside UnhandledException handler: %s\n", msg);
4504 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4507 * mono_runtime_unhandled_exception_policy_set:
4508 * @policy: the new policy
4510 * This is a VM internal routine.
4512 * Sets the runtime policy for handling unhandled exceptions.
4515 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4516 runtime_unhandled_exception_policy = policy;
4520 * mono_runtime_unhandled_exception_policy_get:
4522 * This is a VM internal routine.
4524 * Gets the runtime policy for handling unhandled exceptions.
4526 MonoRuntimeUnhandledExceptionPolicy
4527 mono_runtime_unhandled_exception_policy_get (void) {
4528 return runtime_unhandled_exception_policy;
4532 * mono_unhandled_exception:
4533 * @exc: exception thrown
4535 * This is a VM internal routine.
4537 * We call this function when we detect an unhandled exception
4538 * in the default domain.
4540 * It invokes the * UnhandledException event in AppDomain or prints
4541 * a warning to the console
4544 mono_unhandled_exception (MonoObject *exc)
4546 MONO_REQ_GC_UNSAFE_MODE;
4549 MonoClassField *field;
4550 MonoDomain *current_domain, *root_domain;
4551 MonoObject *current_appdomain_delegate = NULL, *root_appdomain_delegate = NULL;
4553 if (mono_class_has_parent (exc->vtable->klass, mono_defaults.threadabortexception_class))
4556 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4559 current_domain = mono_domain_get ();
4560 root_domain = mono_get_root_domain ();
4562 root_appdomain_delegate = mono_field_get_value_object_checked (root_domain, field, (MonoObject*) root_domain->domain, &error);
4563 mono_error_assert_ok (&error);
4564 if (current_domain != root_domain) {
4565 current_appdomain_delegate = mono_field_get_value_object_checked (current_domain, field, (MonoObject*) current_domain->domain, &error);
4566 mono_error_assert_ok (&error);
4569 if (!current_appdomain_delegate && !root_appdomain_delegate) {
4570 mono_print_unhandled_exception (exc);
4572 /* unhandled exception callbacks must not be aborted */
4573 mono_threads_begin_abort_protected_block ();
4574 if (root_appdomain_delegate)
4575 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4576 if (current_appdomain_delegate)
4577 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4578 mono_threads_end_abort_protected_block ();
4581 /* set exitcode only if we will abort the process */
4582 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4583 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4585 mono_environment_exitcode_set (1);
4590 * mono_runtime_exec_managed_code:
4591 * @domain: Application domain
4592 * @main_func: function to invoke from the execution thread
4593 * @main_args: parameter to the main_func
4595 * Launch a new thread to execute a function
4597 * main_func is called back from the thread with main_args as the
4598 * parameter. The callback function is expected to start Main()
4599 * eventually. This function then waits for all managed threads to
4601 * It is not necesseray anymore to execute managed code in a subthread,
4602 * so this function should not be used anymore by default: just
4603 * execute the code and then call mono_thread_manage ().
4606 mono_runtime_exec_managed_code (MonoDomain *domain,
4607 MonoMainThreadFunc main_func,
4611 mono_thread_create_checked (domain, main_func, main_args, &error);
4612 mono_error_assert_ok (&error);
4614 mono_thread_manage ();
4618 prepare_thread_to_exec_main (MonoDomain *domain, MonoMethod *method)
4620 MonoInternalThread* thread = mono_thread_internal_current ();
4621 MonoCustomAttrInfo* cinfo;
4622 gboolean has_stathread_attribute;
4624 if (!domain->entry_assembly) {
4626 MonoAssembly *assembly;
4628 assembly = method->klass->image->assembly;
4629 domain->entry_assembly = assembly;
4630 /* Domains created from another domain already have application_base and configuration_file set */
4631 if (domain->setup->application_base == NULL) {
4632 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4635 if (domain->setup->configuration_file == NULL) {
4636 str = g_strconcat (assembly->image->name, ".config", NULL);
4637 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4639 mono_domain_set_options_from_config (domain);
4643 MonoError cattr_error;
4644 cinfo = mono_custom_attrs_from_method_checked (method, &cattr_error);
4645 mono_error_cleanup (&cattr_error); /* FIXME warn here? */
4647 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, mono_class_get_sta_thread_attribute_class ());
4649 mono_custom_attrs_free (cinfo);
4651 has_stathread_attribute = FALSE;
4653 if (has_stathread_attribute) {
4654 thread->apartment_state = ThreadApartmentState_STA;
4656 thread->apartment_state = ThreadApartmentState_MTA;
4658 mono_thread_init_apartment_state ();
4663 do_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4665 MONO_REQ_GC_UNSAFE_MODE;
4670 mono_error_init (error);
4675 /* FIXME: check signature of method */
4676 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4678 res = mono_runtime_invoke_checked (method, NULL, pa, error);
4680 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4683 mono_environment_exitcode_set (rval);
4685 mono_runtime_invoke_checked (method, NULL, pa, error);
4697 do_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4699 MONO_REQ_GC_UNSAFE_MODE;
4709 /* FIXME: check signature of method */
4710 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4711 MonoError inner_error;
4713 res = mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4714 if (*exc == NULL && !mono_error_ok (&inner_error))
4715 *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4717 mono_error_cleanup (&inner_error);
4720 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4724 mono_environment_exitcode_set (rval);
4726 MonoError inner_error;
4727 mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4728 if (*exc == NULL && !mono_error_ok (&inner_error))
4729 *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4731 mono_error_cleanup (&inner_error);
4736 /* If the return type of Main is void, only
4737 * set the exitcode if an exception was thrown
4738 * (we don't want to blow away an
4739 * explicitly-set exit code)
4742 mono_environment_exitcode_set (rval);
4750 * Execute a standard Main() method (args doesn't contain the
4754 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4757 prepare_thread_to_exec_main (mono_object_domain (args), method);
4759 int rval = do_try_exec_main (method, args, exc);
4762 int rval = do_exec_main_checked (method, args, &error);
4763 mono_error_raise_exception (&error); /* OK to throw, external only with no better option */
4769 * Execute a standard Main() method (args doesn't contain the
4772 * On failure sets @error
4775 mono_runtime_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4777 mono_error_init (error);
4778 prepare_thread_to_exec_main (mono_object_domain (args), method);
4779 return do_exec_main_checked (method, args, error);
4783 * Execute a standard Main() method (args doesn't contain the
4786 * On failure sets @error if Main couldn't be executed, or @exc if it threw an exception.
4789 mono_runtime_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4791 prepare_thread_to_exec_main (mono_object_domain (args), method);
4792 return do_try_exec_main (method, args, exc);
4797 /** invoke_array_extract_argument:
4798 * @params: array of arguments to the method.
4799 * @i: the index of the argument to extract.
4800 * @t: ith type from the method signature.
4801 * @has_byref_nullables: outarg - TRUE if method expects a byref nullable argument
4802 * @error: set on error.
4804 * Given an array of method arguments, return the ith one using the corresponding type
4805 * to perform necessary unboxing. If method expects a ref nullable argument, writes TRUE to @has_byref_nullables.
4807 * On failure sets @error and returns NULL.
4810 invoke_array_extract_argument (MonoArray *params, int i, MonoType *t, gboolean* has_byref_nullables, MonoError *error)
4812 MonoType *t_orig = t;
4813 gpointer result = NULL;
4814 mono_error_init (error);
4819 case MONO_TYPE_BOOLEAN:
4822 case MONO_TYPE_CHAR:
4831 case MONO_TYPE_VALUETYPE:
4832 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (t_orig))) {
4833 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4834 result = mono_array_get (params, MonoObject*, i);
4836 *has_byref_nullables = TRUE;
4838 /* MS seems to create the objects if a null is passed in */
4839 if (!mono_array_get (params, MonoObject*, i)) {
4840 MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (t_orig), error);
4841 return_val_if_nok (error, NULL);
4842 mono_array_setref (params, i, o);
4847 * We can't pass the unboxed vtype byref to the callee, since
4848 * that would mean the callee would be able to modify boxed
4849 * primitive types. So we (and MS) make a copy of the boxed
4850 * object, pass that to the callee, and replace the original
4851 * boxed object in the arg array with the copy.
4853 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4854 MonoObject *copy = mono_value_box_checked (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig), error);
4855 return_val_if_nok (error, NULL);
4856 mono_array_setref (params, i, copy);
4859 result = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4862 case MONO_TYPE_STRING:
4863 case MONO_TYPE_OBJECT:
4864 case MONO_TYPE_CLASS:
4865 case MONO_TYPE_ARRAY:
4866 case MONO_TYPE_SZARRAY:
4868 result = mono_array_addr (params, MonoObject*, i);
4869 // FIXME: I need to check this code path
4871 result = mono_array_get (params, MonoObject*, i);
4873 case MONO_TYPE_GENERICINST:
4875 t = &t->data.generic_class->container_class->this_arg;
4877 t = &t->data.generic_class->container_class->byval_arg;
4879 case MONO_TYPE_PTR: {
4882 /* The argument should be an IntPtr */
4883 arg = mono_array_get (params, MonoObject*, i);
4887 g_assert (arg->vtable->klass == mono_defaults.int_class);
4888 result = ((MonoIntPtr*)arg)->m_value;
4893 g_error ("type 0x%x not handled in mono_runtime_invoke_array", t_orig->type);
4898 * mono_runtime_invoke_array:
4899 * @method: method to invoke
4900 * @obJ: object instance
4901 * @params: arguments to the method
4902 * @exc: exception information.
4904 * Invokes the method represented by @method on the object @obj.
4906 * obj is the 'this' pointer, it should be NULL for static
4907 * methods, a MonoObject* for object instances and a pointer to
4908 * the value type for value types.
4910 * The params array contains the arguments to the method with the
4911 * same convention: MonoObject* pointers for object instances and
4912 * pointers to the value type otherwise. The _invoke_array
4913 * variant takes a C# object[] as the params argument (MonoArray
4914 * *params): in this case the value types are boxed inside the
4915 * respective reference representation.
4917 * From unmanaged code you'll usually use the
4918 * mono_runtime_invoke_checked() variant.
4920 * Note that this function doesn't handle virtual methods for
4921 * you, it will exec the exact method you pass: we still need to
4922 * expose a function to lookup the derived class implementation
4923 * of a virtual method (there are examples of this in the code,
4926 * You can pass NULL as the exc argument if you don't want to
4927 * catch exceptions, otherwise, *exc will be set to the exception
4928 * thrown, if any. if an exception is thrown, you can't use the
4929 * MonoObject* result from the function.
4931 * If the method returns a value type, it is boxed in an object
4935 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4940 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, exc, &error);
4942 mono_error_cleanup (&error);
4945 if (!is_ok (&error))
4946 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
4950 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, NULL, &error);
4951 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
4957 * mono_runtime_invoke_array_checked:
4958 * @method: method to invoke
4959 * @obJ: object instance
4960 * @params: arguments to the method
4961 * @error: set on failure.
4963 * Invokes the method represented by @method on the object @obj.
4965 * obj is the 'this' pointer, it should be NULL for static
4966 * methods, a MonoObject* for object instances and a pointer to
4967 * the value type for value types.
4969 * The params array contains the arguments to the method with the
4970 * same convention: MonoObject* pointers for object instances and
4971 * pointers to the value type otherwise. The _invoke_array
4972 * variant takes a C# object[] as the params argument (MonoArray
4973 * *params): in this case the value types are boxed inside the
4974 * respective reference representation.
4976 * From unmanaged code you'll usually use the
4977 * mono_runtime_invoke_checked() variant.
4979 * Note that this function doesn't handle virtual methods for
4980 * you, it will exec the exact method you pass: we still need to
4981 * expose a function to lookup the derived class implementation
4982 * of a virtual method (there are examples of this in the code,
4985 * On failure or exception, @error will be set. In that case, you
4986 * can't use the MonoObject* result from the function.
4988 * If the method returns a value type, it is boxed in an object
4992 mono_runtime_invoke_array_checked (MonoMethod *method, void *obj, MonoArray *params,
4995 mono_error_init (error);
4996 return mono_runtime_try_invoke_array (method, obj, params, NULL, error);
5000 * mono_runtime_try_invoke_array:
5001 * @method: method to invoke
5002 * @obJ: object instance
5003 * @params: arguments to the method
5004 * @exc: exception information.
5005 * @error: set on failure.
5007 * Invokes the method represented by @method on the object @obj.
5009 * obj is the 'this' pointer, it should be NULL for static
5010 * methods, a MonoObject* for object instances and a pointer to
5011 * the value type for value types.
5013 * The params array contains the arguments to the method with the
5014 * same convention: MonoObject* pointers for object instances and
5015 * pointers to the value type otherwise. The _invoke_array
5016 * variant takes a C# object[] as the params argument (MonoArray
5017 * *params): in this case the value types are boxed inside the
5018 * respective reference representation.
5020 * From unmanaged code you'll usually use the
5021 * mono_runtime_invoke_checked() variant.
5023 * Note that this function doesn't handle virtual methods for
5024 * you, it will exec the exact method you pass: we still need to
5025 * expose a function to lookup the derived class implementation
5026 * of a virtual method (there are examples of this in the code,
5029 * You can pass NULL as the exc argument if you don't want to catch
5030 * exceptions, otherwise, *exc will be set to the exception thrown, if
5031 * any. On other failures, @error will be set. If an exception is
5032 * thrown or there's an error, you can't use the MonoObject* result
5033 * from the function.
5035 * If the method returns a value type, it is boxed in an object
5039 mono_runtime_try_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
5040 MonoObject **exc, MonoError *error)
5042 MONO_REQ_GC_UNSAFE_MODE;
5044 mono_error_init (error);
5046 MonoMethodSignature *sig = mono_method_signature (method);
5047 gpointer *pa = NULL;
5050 gboolean has_byref_nullables = FALSE;
5052 if (NULL != params) {
5053 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
5054 for (i = 0; i < mono_array_length (params); i++) {
5055 MonoType *t = sig->params [i];
5056 pa [i] = invoke_array_extract_argument (params, i, t, &has_byref_nullables, error);
5057 return_val_if_nok (error, NULL);
5061 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
5064 if (mono_class_is_nullable (method->klass)) {
5065 /* Need to create a boxed vtype instead */
5071 return mono_value_box_checked (mono_domain_get (), method->klass->cast_class, pa [0], error);
5076 obj = mono_object_new_checked (mono_domain_get (), method->klass, error);
5077 mono_error_assert_ok (error);
5078 g_assert (obj); /*maybe we should raise a TLE instead?*/
5079 #ifndef DISABLE_REMOTING
5080 if (mono_object_is_transparent_proxy (obj)) {
5081 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
5084 if (method->klass->valuetype)
5085 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
5088 } else if (method->klass->valuetype) {
5089 obj = mono_value_box_checked (mono_domain_get (), method->klass, obj, error);
5090 return_val_if_nok (error, NULL);
5094 mono_runtime_try_invoke (method, o, pa, exc, error);
5096 mono_runtime_invoke_checked (method, o, pa, error);
5099 return (MonoObject *)obj;
5101 if (mono_class_is_nullable (method->klass)) {
5102 MonoObject *nullable;
5104 /* Convert the unboxed vtype into a Nullable structure */
5105 nullable = mono_object_new_checked (mono_domain_get (), method->klass, error);
5106 return_val_if_nok (error, NULL);
5108 MonoObject *boxed = mono_value_box_checked (mono_domain_get (), method->klass->cast_class, obj, error);
5109 return_val_if_nok (error, NULL);
5110 mono_nullable_init ((guint8 *)mono_object_unbox (nullable), boxed, method->klass);
5111 obj = mono_object_unbox (nullable);
5114 /* obj must be already unboxed if needed */
5116 res = mono_runtime_try_invoke (method, obj, pa, exc, error);
5118 res = mono_runtime_invoke_checked (method, obj, pa, error);
5120 return_val_if_nok (error, NULL);
5122 if (sig->ret->type == MONO_TYPE_PTR) {
5123 MonoClass *pointer_class;
5124 static MonoMethod *box_method;
5126 MonoObject *box_exc;
5129 * The runtime-invoke wrapper returns a boxed IntPtr, need to
5130 * convert it to a Pointer object.
5132 pointer_class = mono_class_get_pointer_class ();
5134 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
5136 g_assert (res->vtable->klass == mono_defaults.int_class);
5137 box_args [0] = ((MonoIntPtr*)res)->m_value;
5138 box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, error);
5139 return_val_if_nok (error, NULL);
5141 res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, error);
5142 g_assert (box_exc == NULL);
5143 mono_error_assert_ok (error);
5146 if (has_byref_nullables) {
5148 * The runtime invoke wrapper already converted byref nullables back,
5149 * and stored them in pa, we just need to copy them back to the
5152 for (i = 0; i < mono_array_length (params); i++) {
5153 MonoType *t = sig->params [i];
5155 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
5156 mono_array_setref (params, i, pa [i]);
5166 * @klass: the class of the object that we want to create
5168 * Returns: a newly created object whose definition is
5169 * looked up using @klass. This will not invoke any constructors,
5170 * so the consumer of this routine has to invoke any constructors on
5171 * its own to initialize the object.
5173 * It returns NULL on failure.
5176 mono_object_new (MonoDomain *domain, MonoClass *klass)
5178 MONO_REQ_GC_UNSAFE_MODE;
5182 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5184 mono_error_cleanup (&error);
5189 ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
5191 MONO_REQ_GC_UNSAFE_MODE;
5195 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5197 mono_error_set_pending_exception (&error);
5202 * mono_object_new_checked:
5203 * @klass: the class of the object that we want to create
5204 * @error: set on error
5206 * Returns: a newly created object whose definition is
5207 * looked up using @klass. This will not invoke any constructors,
5208 * so the consumer of this routine has to invoke any constructors on
5209 * its own to initialize the object.
5211 * It returns NULL on failure and sets @error.
5214 mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
5216 MONO_REQ_GC_UNSAFE_MODE;
5220 vtable = mono_class_vtable (domain, klass);
5221 g_assert (vtable); /* FIXME don't swallow the error */
5223 MonoObject *o = mono_object_new_specific_checked (vtable, error);
5228 * mono_object_new_pinned:
5230 * Same as mono_object_new, but the returned object will be pinned.
5231 * For SGEN, these objects will only be freed at appdomain unload.
5234 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
5236 MONO_REQ_GC_UNSAFE_MODE;
5240 mono_error_init (error);
5242 vtable = mono_class_vtable (domain, klass);
5243 g_assert (vtable); /* FIXME don't swallow the error */
5245 MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
5247 if (G_UNLIKELY (!o))
5248 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
5249 else if (G_UNLIKELY (vtable->klass->has_finalize))
5250 mono_object_register_finalizer (o);
5256 * mono_object_new_specific:
5257 * @vtable: the vtable of the object that we want to create
5259 * Returns: A newly created object with class and domain specified
5263 mono_object_new_specific (MonoVTable *vtable)
5266 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5267 mono_error_cleanup (&error);
5273 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
5275 MONO_REQ_GC_UNSAFE_MODE;
5279 mono_error_init (error);
5281 /* check for is_com_object for COM Interop */
5282 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
5285 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
5288 MonoClass *klass = mono_class_get_activation_services_class ();
5291 mono_class_init (klass);
5293 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
5295 mono_error_set_not_supported (error, "Linked away.");
5298 vtable->domain->create_proxy_for_type_method = im;
5301 pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
5302 if (!mono_error_ok (error))
5305 o = mono_runtime_invoke_checked (im, NULL, pa, error);
5306 if (!mono_error_ok (error))
5313 return mono_object_new_alloc_specific_checked (vtable, error);
5317 ves_icall_object_new_specific (MonoVTable *vtable)
5320 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5321 mono_error_set_pending_exception (&error);
5327 * mono_object_new_alloc_specific:
5328 * @vtable: virtual table for the object.
5330 * This function allocates a new `MonoObject` with the type derived
5331 * from the @vtable information. If the class of this object has a
5332 * finalizer, then the object will be tracked for finalization.
5334 * This method might raise an exception on errors. Use the
5335 * `mono_object_new_fast_checked` method if you want to manually raise
5338 * Returns: the allocated object.
5341 mono_object_new_alloc_specific (MonoVTable *vtable)
5344 MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
5345 mono_error_cleanup (&error);
5351 * mono_object_new_alloc_specific_checked:
5352 * @vtable: virtual table for the object.
5353 * @error: holds the error return value.
5355 * This function allocates a new `MonoObject` with the type derived
5356 * from the @vtable information. If the class of this object has a
5357 * finalizer, then the object will be tracked for finalization.
5359 * If there is not enough memory, the @error parameter will be set
5360 * and will contain a user-visible message with the amount of bytes
5361 * that were requested.
5363 * Returns: the allocated object, or NULL if there is not enough memory
5367 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
5369 MONO_REQ_GC_UNSAFE_MODE;
5373 mono_error_init (error);
5375 o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5377 if (G_UNLIKELY (!o))
5378 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5379 else if (G_UNLIKELY (vtable->klass->has_finalize))
5380 mono_object_register_finalizer (o);
5386 * mono_object_new_fast:
5387 * @vtable: virtual table for the object.
5389 * This function allocates a new `MonoObject` with the type derived
5390 * from the @vtable information. The returned object is not tracked
5391 * for finalization. If your object implements a finalizer, you should
5392 * use `mono_object_new_alloc_specific` instead.
5394 * This method might raise an exception on errors. Use the
5395 * `mono_object_new_fast_checked` method if you want to manually raise
5398 * Returns: the allocated object.
5401 mono_object_new_fast (MonoVTable *vtable)
5404 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5405 mono_error_cleanup (&error);
5411 * mono_object_new_fast_checked:
5412 * @vtable: virtual table for the object.
5413 * @error: holds the error return value.
5415 * This function allocates a new `MonoObject` with the type derived
5416 * from the @vtable information. The returned object is not tracked
5417 * for finalization. If your object implements a finalizer, you should
5418 * use `mono_object_new_alloc_specific_checked` instead.
5420 * If there is not enough memory, the @error parameter will be set
5421 * and will contain a user-visible message with the amount of bytes
5422 * that were requested.
5424 * Returns: the allocated object, or NULL if there is not enough memory
5428 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
5430 MONO_REQ_GC_UNSAFE_MODE;
5434 mono_error_init (error);
5436 o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5438 if (G_UNLIKELY (!o))
5439 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5445 ves_icall_object_new_fast (MonoVTable *vtable)
5448 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5449 mono_error_set_pending_exception (&error);
5455 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
5457 MONO_REQ_GC_UNSAFE_MODE;
5461 mono_error_init (error);
5463 o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
5465 if (G_UNLIKELY (!o))
5466 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5467 else if (G_UNLIKELY (vtable->klass->has_finalize))
5468 mono_object_register_finalizer (o);
5474 * mono_class_get_allocation_ftn:
5476 * @for_box: the object will be used for boxing
5477 * @pass_size_in_words:
5479 * Return the allocation function appropriate for the given class.
5483 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
5485 MONO_REQ_GC_NEUTRAL_MODE;
5487 *pass_size_in_words = FALSE;
5489 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass))
5490 return ves_icall_object_new_specific;
5492 if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
5494 return ves_icall_object_new_fast;
5497 * FIXME: This is actually slower than ves_icall_object_new_fast, because
5498 * of the overhead of parameter passing.
5501 *pass_size_in_words = TRUE;
5502 #ifdef GC_REDIRECT_TO_LOCAL
5503 return GC_local_gcj_fast_malloc;
5505 return GC_gcj_fast_malloc;
5510 return ves_icall_object_new_specific;
5514 * mono_object_new_from_token:
5515 * @image: Context where the type_token is hosted
5516 * @token: a token of the type that we want to create
5518 * Returns: A newly created object whose definition is
5519 * looked up using @token in the @image image
5522 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
5524 MONO_REQ_GC_UNSAFE_MODE;
5530 klass = mono_class_get_checked (image, token, &error);
5531 mono_error_assert_ok (&error);
5533 result = mono_object_new_checked (domain, klass, &error);
5535 mono_error_cleanup (&error);
5542 * mono_object_clone:
5543 * @obj: the object to clone
5545 * Returns: A newly created object who is a shallow copy of @obj
5548 mono_object_clone (MonoObject *obj)
5551 MonoObject *o = mono_object_clone_checked (obj, &error);
5552 mono_error_cleanup (&error);
5558 mono_object_clone_checked (MonoObject *obj, MonoError *error)
5560 MONO_REQ_GC_UNSAFE_MODE;
5565 mono_error_init (error);
5567 size = obj->vtable->klass->instance_size;
5569 if (obj->vtable->klass->rank)
5570 return (MonoObject*)mono_array_clone_checked ((MonoArray*)obj, error);
5572 o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
5574 if (G_UNLIKELY (!o)) {
5575 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5579 /* If the object doesn't contain references this will do a simple memmove. */
5580 mono_gc_wbarrier_object_copy (o, obj);
5582 if (obj->vtable->klass->has_finalize)
5583 mono_object_register_finalizer (o);
5588 * mono_array_full_copy:
5589 * @src: source array to copy
5590 * @dest: destination array
5592 * Copies the content of one array to another with exactly the same type and size.
5595 mono_array_full_copy (MonoArray *src, MonoArray *dest)
5597 MONO_REQ_GC_UNSAFE_MODE;
5600 MonoClass *klass = src->obj.vtable->klass;
5602 g_assert (klass == dest->obj.vtable->klass);
5604 size = mono_array_length (src);
5605 g_assert (size == mono_array_length (dest));
5606 size *= mono_array_element_size (klass);
5608 array_full_copy_unchecked_size (src, dest, klass, size);
5612 array_full_copy_unchecked_size (MonoArray *src, MonoArray *dest, MonoClass *klass, uintptr_t size)
5615 if (klass->element_class->valuetype) {
5616 if (klass->element_class->has_references)
5617 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
5619 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5621 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
5624 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5629 * mono_array_clone_in_domain:
5630 * @domain: the domain in which the array will be cloned into
5631 * @array: the array to clone
5632 * @error: set on error
5634 * This routine returns a copy of the array that is hosted on the
5635 * specified MonoDomain. On failure returns NULL and sets @error.
5638 mono_array_clone_in_domain (MonoDomain *domain, MonoArrayHandle array_handle, MonoError *error)
5640 MONO_REQ_GC_UNSAFE_MODE;
5642 MonoArrayHandle result = MONO_HANDLE_NEW (MonoArray, NULL);
5644 MonoClass *klass = mono_handle_class (array_handle);
5646 mono_error_init (error);
5648 /* Pin source array here - if bounds is non-NULL, it's a pointer into the object data */
5649 uint32_t src_handle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, array_handle), TRUE);
5651 MonoArrayBounds *array_bounds = MONO_HANDLE_GETVAL (array_handle, bounds);
5653 if (array_bounds == NULL) {
5654 size = mono_array_handle_length (array_handle);
5655 o = mono_array_new_full_handle (domain, klass, &size, NULL, error);
5658 size *= mono_array_element_size (klass);
5660 uintptr_t *sizes = (uintptr_t *)alloca (klass->rank * sizeof (uintptr_t));
5661 intptr_t *lower_bounds = (intptr_t *)alloca (klass->rank * sizeof (intptr_t));
5662 size = mono_array_element_size (klass);
5663 for (int i = 0; i < klass->rank; ++i) {
5664 sizes [i] = array_bounds [i].length;
5665 size *= array_bounds [i].length;
5666 lower_bounds [i] = array_bounds [i].lower_bound;
5668 o = mono_array_new_full_handle (domain, klass, sizes, lower_bounds, error);
5673 uint32_t dst_handle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, o), TRUE);
5674 array_full_copy_unchecked_size (MONO_HANDLE_RAW (array_handle), MONO_HANDLE_RAW (o), klass, size);
5675 mono_gchandle_free (dst_handle);
5677 MONO_HANDLE_ASSIGN (result, o);
5680 mono_gchandle_free (src_handle);
5686 * @array: the array to clone
5688 * Returns: A newly created array who is a shallow copy of @array
5691 mono_array_clone (MonoArray *array)
5693 MONO_REQ_GC_UNSAFE_MODE;
5696 MonoArray *result = mono_array_clone_checked (array, &error);
5697 mono_error_cleanup (&error);
5702 * mono_array_clone_checked:
5703 * @array: the array to clone
5704 * @error: set on error
5706 * Returns: A newly created array who is a shallow copy of @array. On
5707 * failure returns NULL and sets @error.
5710 mono_array_clone_checked (MonoArray *array_raw, MonoError *error)
5712 MONO_REQ_GC_UNSAFE_MODE;
5713 HANDLE_FUNCTION_ENTER ();
5714 /* FIXME: callers of mono_array_clone_checked should use handles */
5715 mono_error_init (error);
5716 MONO_HANDLE_DCL (MonoArray, array);
5717 MonoArrayHandle result = mono_array_clone_in_domain (MONO_HANDLE_DOMAIN (array), array, error);
5718 HANDLE_FUNCTION_RETURN_OBJ (result);
5721 /* helper macros to check for overflow when calculating the size of arrays */
5722 #ifdef MONO_BIG_ARRAYS
5723 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
5724 #define MYGUINT_MAX MYGUINT64_MAX
5725 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5726 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
5727 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5728 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
5729 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
5731 #define MYGUINT32_MAX 4294967295U
5732 #define MYGUINT_MAX MYGUINT32_MAX
5733 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5734 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
5735 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5736 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
5737 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
5741 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
5743 MONO_REQ_GC_NEUTRAL_MODE;
5747 byte_len = mono_array_element_size (klass);
5748 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
5751 if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
5753 byte_len += MONO_SIZEOF_MONO_ARRAY;
5761 * mono_array_new_full:
5762 * @domain: domain where the object is created
5763 * @array_class: array class
5764 * @lengths: lengths for each dimension in the array
5765 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
5767 * This routine creates a new array objects with the given dimensions,
5768 * lower bounds and type.
5771 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
5774 MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
5775 mono_error_cleanup (&error);
5781 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
5783 MONO_REQ_GC_UNSAFE_MODE;
5785 uintptr_t byte_len = 0, len, bounds_size;
5788 MonoArrayBounds *bounds;
5792 mono_error_init (error);
5794 if (!array_class->inited)
5795 mono_class_init (array_class);
5799 /* A single dimensional array with a 0 lower bound is the same as an szarray */
5800 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
5802 if (len > MONO_ARRAY_MAX_INDEX) {
5803 mono_error_set_generic_error (error, "System", "OverflowException", "");
5808 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
5810 for (i = 0; i < array_class->rank; ++i) {
5811 if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
5812 mono_error_set_generic_error (error, "System", "OverflowException", "");
5815 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5816 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5823 if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5824 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5830 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5831 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5834 byte_len = (byte_len + 3) & ~3;
5835 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5836 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5839 byte_len += bounds_size;
5842 * Following three lines almost taken from mono_object_new ():
5843 * they need to be kept in sync.
5845 vtable = mono_class_vtable_full (domain, array_class, error);
5846 return_val_if_nok (error, NULL);
5849 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5851 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5853 if (G_UNLIKELY (!o)) {
5854 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5858 array = (MonoArray*)o;
5860 bounds = array->bounds;
5863 for (i = 0; i < array_class->rank; ++i) {
5864 bounds [i].length = lengths [i];
5866 bounds [i].lower_bound = lower_bounds [i];
5875 * @domain: domain where the object is created
5876 * @eclass: element class
5877 * @n: number of array elements
5879 * This routine creates a new szarray with @n elements of type @eclass.
5882 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5884 MONO_REQ_GC_UNSAFE_MODE;
5887 MonoArray *result = mono_array_new_checked (domain, eclass, n, &error);
5888 mono_error_cleanup (&error);
5893 * mono_array_new_checked:
5894 * @domain: domain where the object is created
5895 * @eclass: element class
5896 * @n: number of array elements
5897 * @error: set on error
5899 * This routine creates a new szarray with @n elements of type @eclass.
5900 * On failure returns NULL and sets @error.
5903 mono_array_new_checked (MonoDomain *domain, MonoClass *eclass, uintptr_t n, MonoError *error)
5907 mono_error_init (error);
5909 ac = mono_array_class_get (eclass, 1);
5912 MonoVTable *vtable = mono_class_vtable_full (domain, ac, error);
5913 return_val_if_nok (error, NULL);
5915 return mono_array_new_specific_checked (vtable, n, error);
5919 ves_icall_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5922 MonoArray *arr = mono_array_new_checked (domain, eclass, n, &error);
5923 mono_error_set_pending_exception (&error);
5929 * mono_array_new_specific:
5930 * @vtable: a vtable in the appropriate domain for an initialized class
5931 * @n: number of array elements
5933 * This routine is a fast alternative to mono_array_new() for code which
5934 * can be sure about the domain it operates in.
5937 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5940 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5941 mono_error_cleanup (&error);
5947 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
5949 MONO_REQ_GC_UNSAFE_MODE;
5954 mono_error_init (error);
5956 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
5957 mono_error_set_generic_error (error, "System", "OverflowException", "");
5961 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
5962 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5965 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
5967 if (G_UNLIKELY (!o)) {
5968 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5972 return (MonoArray*)o;
5976 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
5979 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5980 mono_error_set_pending_exception (&error);
5986 * mono_string_empty_wrapper:
5988 * Returns: The same empty string instance as the managed string.Empty
5991 mono_string_empty_wrapper (void)
5993 MonoDomain *domain = mono_domain_get ();
5994 return mono_string_empty (domain);
5998 * mono_string_empty:
6000 * Returns: The same empty string instance as the managed string.Empty
6003 mono_string_empty (MonoDomain *domain)
6006 g_assert (domain->empty_string);
6007 return domain->empty_string;
6011 * mono_string_new_utf16:
6012 * @text: a pointer to an utf16 string
6013 * @len: the length of the string
6015 * Returns: A newly created string object which contains @text.
6018 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
6020 MONO_REQ_GC_UNSAFE_MODE;
6023 MonoString *res = NULL;
6024 res = mono_string_new_utf16_checked (domain, text, len, &error);
6025 mono_error_cleanup (&error);
6031 * mono_string_new_utf16_checked:
6032 * @text: a pointer to an utf16 string
6033 * @len: the length of the string
6034 * @error: written on error.
6036 * Returns: A newly created string object which contains @text.
6037 * On error, returns NULL and sets @error.
6040 mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
6042 MONO_REQ_GC_UNSAFE_MODE;
6046 mono_error_init (error);
6048 s = mono_string_new_size_checked (domain, len, error);
6050 memcpy (mono_string_chars (s), text, len * 2);
6056 * mono_string_new_utf16_handle:
6057 * @text: a pointer to an utf16 string
6058 * @len: the length of the string
6059 * @error: written on error.
6061 * Returns: A newly created string object which contains @text.
6062 * On error, returns NULL and sets @error.
6065 mono_string_new_utf16_handle (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
6067 return MONO_HANDLE_NEW (MonoString, mono_string_new_utf16_checked (domain, text, len, error));
6071 * mono_string_new_utf32:
6072 * @text: a pointer to an utf32 string
6073 * @len: the length of the string
6074 * @error: set on failure.
6076 * Returns: A newly created string object which contains @text. On failure returns NULL and sets @error.
6079 mono_string_new_utf32_checked (MonoDomain *domain, const mono_unichar4 *text, gint32 len, MonoError *error)
6081 MONO_REQ_GC_UNSAFE_MODE;
6084 mono_unichar2 *utf16_output = NULL;
6085 gint32 utf16_len = 0;
6086 GError *gerror = NULL;
6087 glong items_written;
6089 mono_error_init (error);
6090 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
6093 g_error_free (gerror);
6095 while (utf16_output [utf16_len]) utf16_len++;
6097 s = mono_string_new_size_checked (domain, utf16_len, error);
6098 return_val_if_nok (error, NULL);
6100 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
6102 g_free (utf16_output);
6108 * mono_string_new_utf32:
6109 * @text: a pointer to an utf32 string
6110 * @len: the length of the string
6112 * Returns: A newly created string object which contains @text.
6115 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
6118 MonoString *result = mono_string_new_utf32_checked (domain, text, len, &error);
6119 mono_error_cleanup (&error);
6124 * mono_string_new_size:
6125 * @text: a pointer to an utf16 string
6126 * @len: the length of the string
6128 * Returns: A newly created string object of @len
6131 mono_string_new_size (MonoDomain *domain, gint32 len)
6134 MonoString *str = mono_string_new_size_checked (domain, len, &error);
6135 mono_error_cleanup (&error);
6141 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
6143 MONO_REQ_GC_UNSAFE_MODE;
6149 mono_error_init (error);
6151 /* check for overflow */
6152 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
6153 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
6157 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
6158 g_assert (size > 0);
6160 vtable = mono_class_vtable (domain, mono_defaults.string_class);
6163 s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
6165 if (G_UNLIKELY (!s)) {
6166 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", size);
6174 * mono_string_new_len:
6175 * @text: a pointer to an utf8 string
6176 * @length: number of bytes in @text to consider
6178 * Returns: A newly created string object which contains @text.
6181 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
6183 MONO_REQ_GC_UNSAFE_MODE;
6186 MonoString *result = mono_string_new_len_checked (domain, text, length, &error);
6187 mono_error_cleanup (&error);
6192 * mono_string_new_len_checked:
6193 * @text: a pointer to an utf8 string
6194 * @length: number of bytes in @text to consider
6195 * @error: set on error
6197 * Returns: A newly created string object which contains @text. On
6198 * failure returns NULL and sets @error.
6201 mono_string_new_len_checked (MonoDomain *domain, const char *text, guint length, MonoError *error)
6203 MONO_REQ_GC_UNSAFE_MODE;
6205 mono_error_init (error);
6207 GError *eg_error = NULL;
6208 MonoString *o = NULL;
6210 glong items_written;
6212 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
6215 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6217 g_error_free (eg_error);
6226 * @text: a pointer to an utf8 string
6228 * Returns: A newly created string object which contains @text.
6230 * This function asserts if it cannot allocate a new string.
6232 * @deprecated Use mono_string_new_checked in new code.
6235 mono_string_new (MonoDomain *domain, const char *text)
6238 MonoString *res = NULL;
6239 res = mono_string_new_checked (domain, text, &error);
6240 mono_error_assert_ok (&error);
6245 * mono_string_new_checked:
6246 * @text: a pointer to an utf8 string
6247 * @merror: set on error
6249 * Returns: A newly created string object which contains @text.
6250 * On error returns NULL and sets @merror.
6253 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
6255 MONO_REQ_GC_UNSAFE_MODE;
6257 GError *eg_error = NULL;
6258 MonoString *o = NULL;
6260 glong items_written;
6263 mono_error_init (error);
6267 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &eg_error);
6270 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6272 g_error_free (eg_error);
6276 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
6281 MonoString *o = NULL;
6283 if (!g_utf8_validate (text, -1, &end)) {
6284 mono_error_set_argument (error, "text", "Not a valid utf8 string");
6288 len = g_utf8_strlen (text, -1);
6289 o = mono_string_new_size_checked (domain, len, error);
6292 str = mono_string_chars (o);
6294 while (text < end) {
6295 *str++ = g_utf8_get_char (text);
6296 text = g_utf8_next_char (text);
6305 * mono_string_new_wrapper:
6306 * @text: pointer to utf8 characters.
6308 * Helper function to create a string object from @text in the current domain.
6311 mono_string_new_wrapper (const char *text)
6313 MONO_REQ_GC_UNSAFE_MODE;
6315 MonoDomain *domain = mono_domain_get ();
6318 return mono_string_new (domain, text);
6325 * @class: the class of the value
6326 * @value: a pointer to the unboxed data
6328 * Returns: A newly created object which contains @value.
6331 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
6334 MonoObject *result = mono_value_box_checked (domain, klass, value, &error);
6335 mono_error_cleanup (&error);
6340 * mono_value_box_checked:
6341 * @domain: the domain of the new object
6342 * @class: the class of the value
6343 * @value: a pointer to the unboxed data
6344 * @error: set on error
6346 * Returns: A newly created object which contains @value. On failure
6347 * returns NULL and sets @error.
6350 mono_value_box_checked (MonoDomain *domain, MonoClass *klass, gpointer value, MonoError *error)
6352 MONO_REQ_GC_UNSAFE_MODE;
6357 mono_error_init (error);
6359 g_assert (klass->valuetype);
6360 if (mono_class_is_nullable (klass))
6361 return mono_nullable_box ((guint8 *)value, klass, error);
6363 vtable = mono_class_vtable (domain, klass);
6366 size = mono_class_instance_size (klass);
6367 res = mono_object_new_alloc_specific_checked (vtable, error);
6368 return_val_if_nok (error, NULL);
6370 size = size - sizeof (MonoObject);
6373 g_assert (size == mono_class_value_size (klass, NULL));
6374 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
6376 #if NO_UNALIGNED_ACCESS
6377 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6381 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
6384 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
6387 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
6390 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
6393 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6397 if (klass->has_finalize) {
6398 mono_object_register_finalizer (res);
6399 return_val_if_nok (error, NULL);
6406 * @dest: destination pointer
6407 * @src: source pointer
6408 * @klass: a valuetype class
6410 * Copy a valuetype from @src to @dest. This function must be used
6411 * when @klass contains references fields.
6414 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
6416 MONO_REQ_GC_UNSAFE_MODE;
6418 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
6422 * mono_value_copy_array:
6423 * @dest: destination array
6424 * @dest_idx: index in the @dest array
6425 * @src: source pointer
6426 * @count: number of items
6428 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
6429 * This function must be used when @klass contains references fields.
6430 * Overlap is handled.
6433 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
6435 MONO_REQ_GC_UNSAFE_MODE;
6437 int size = mono_array_element_size (dest->obj.vtable->klass);
6438 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
6439 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
6440 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
6444 * mono_object_get_domain:
6445 * @obj: object to query
6447 * Returns: the MonoDomain where the object is hosted
6450 mono_object_get_domain (MonoObject *obj)
6452 MONO_REQ_GC_UNSAFE_MODE;
6454 return mono_object_domain (obj);
6458 * mono_object_get_class:
6459 * @obj: object to query
6461 * Use this function to obtain the `MonoClass*` for a given `MonoObject`.
6463 * Returns: the MonoClass of the object.
6466 mono_object_get_class (MonoObject *obj)
6468 MONO_REQ_GC_UNSAFE_MODE;
6470 return mono_object_class (obj);
6473 * mono_object_get_size:
6474 * @o: object to query
6476 * Returns: the size, in bytes, of @o
6479 mono_object_get_size (MonoObject* o)
6481 MONO_REQ_GC_UNSAFE_MODE;
6483 MonoClass* klass = mono_object_class (o);
6484 if (klass == mono_defaults.string_class) {
6485 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
6486 } else if (o->vtable->rank) {
6487 MonoArray *array = (MonoArray*)o;
6488 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
6489 if (array->bounds) {
6492 size += sizeof (MonoArrayBounds) * o->vtable->rank;
6496 return mono_class_instance_size (klass);
6501 * mono_object_unbox:
6502 * @obj: object to unbox
6504 * Returns: a pointer to the start of the valuetype boxed in this
6507 * This method will assert if the object passed is not a valuetype.
6510 mono_object_unbox (MonoObject *obj)
6512 MONO_REQ_GC_UNSAFE_MODE;
6514 /* add assert for valuetypes? */
6515 g_assert (obj->vtable->klass->valuetype);
6516 return ((char*)obj) + sizeof (MonoObject);
6520 * mono_object_isinst:
6522 * @klass: a pointer to a class
6524 * Returns: @obj if @obj is derived from @klass or NULL otherwise.
6527 mono_object_isinst (MonoObject *obj_raw, MonoClass *klass)
6529 MONO_REQ_GC_UNSAFE_MODE;
6531 HANDLE_FUNCTION_ENTER ();
6532 MONO_HANDLE_DCL (MonoObject, obj);
6534 MonoObjectHandle result = mono_object_handle_isinst (obj, klass, &error);
6535 mono_error_cleanup (&error);
6536 HANDLE_FUNCTION_RETURN_OBJ (result);
6541 * mono_object_isinst_checked:
6543 * @klass: a pointer to a class
6544 * @error: set on error
6546 * Returns: @obj if @obj is derived from @klass or NULL if it isn't.
6547 * On failure returns NULL and sets @error.
6550 mono_object_isinst_checked (MonoObject *obj_raw, MonoClass *klass, MonoError *error)
6552 MONO_REQ_GC_UNSAFE_MODE;
6554 HANDLE_FUNCTION_ENTER ();
6555 mono_error_init (error);
6556 MONO_HANDLE_DCL (MonoObject, obj);
6557 MonoObjectHandle result = mono_object_handle_isinst (obj, klass, error);
6558 HANDLE_FUNCTION_RETURN_OBJ (result);
6562 * mono_object_handle_isinst:
6564 * @klass: a pointer to a class
6565 * @error: set on error
6567 * Returns: @obj if @obj is derived from @klass or NULL if it isn't.
6568 * On failure returns NULL and sets @error.
6571 mono_object_handle_isinst (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
6573 mono_error_init (error);
6576 mono_class_init (klass);
6578 if (mono_class_is_marshalbyref (klass) || mono_class_is_interface (klass)) {
6579 return mono_object_handle_isinst_mbyref (obj, klass, error);
6582 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6584 if (!MONO_HANDLE_IS_NULL (obj) && mono_class_is_assignable_from (klass, mono_handle_class (obj)))
6585 MONO_HANDLE_ASSIGN (result, obj);
6590 mono_object_isinst_mbyref (MonoObject *obj_raw, MonoClass *klass)
6592 MONO_REQ_GC_UNSAFE_MODE;
6594 HANDLE_FUNCTION_ENTER ();
6596 MONO_HANDLE_DCL (MonoObject, obj);
6597 MonoObjectHandle result = mono_object_handle_isinst_mbyref (obj, klass, &error);
6598 mono_error_cleanup (&error); /* FIXME better API that doesn't swallow the error */
6599 HANDLE_FUNCTION_RETURN_OBJ (result);
6603 mono_object_handle_isinst_mbyref (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
6605 mono_error_init (error);
6607 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6609 if (MONO_HANDLE_IS_NULL (obj))
6612 MonoVTable *vt = MONO_HANDLE_GETVAL (obj, vtable);
6614 if (mono_class_is_interface (klass)) {
6615 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
6616 MONO_HANDLE_ASSIGN (result, obj);
6620 /* casting an array one of the invariant interfaces that must act as such */
6621 if (klass->is_array_special_interface) {
6622 if (mono_class_is_assignable_from (klass, vt->klass)) {
6623 MONO_HANDLE_ASSIGN (result, obj);
6628 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
6629 else if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, mono_handle_class (obj))) {
6630 MONO_HANDLE_ASSIGN (result, obj);
6634 MonoClass *oklass = vt->klass;
6635 if (mono_class_is_transparent_proxy (oklass)){
6636 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), remote_class);
6637 oklass = remote_class->proxy_class;
6640 mono_class_setup_supertypes (klass);
6641 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass)) {
6642 MONO_HANDLE_ASSIGN (result, obj);
6646 #ifndef DISABLE_REMOTING
6647 if (mono_class_is_transparent_proxy (vt->klass))
6649 MonoBoolean custom_type_info = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), custom_type_info);
6650 if (!custom_type_info)
6652 MonoDomain *domain = mono_domain_get ();
6653 MonoObjectHandle rp = MONO_HANDLE_NEW (MonoObject, NULL);
6654 MONO_HANDLE_GET (rp, MONO_HANDLE_CAST (MonoTransparentProxy, obj), rp);
6655 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
6656 MonoMethod *im = NULL;
6659 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
6661 mono_error_set_not_supported (error, "Linked away.");
6664 im = mono_object_handle_get_virtual_method (rp, im, error);
6669 MonoReflectionTypeHandle reftype = mono_type_get_object_handle (domain, &klass->byval_arg, error);
6673 pa [0] = MONO_HANDLE_RAW (reftype);
6674 pa [1] = MONO_HANDLE_RAW (obj);
6675 MonoObject *res = mono_runtime_invoke_checked (im, rp, pa, error);
6679 if (*(MonoBoolean *) mono_object_unbox(res)) {
6680 /* Update the vtable of the remote type, so it can safely cast to this new type */
6681 mono_upgrade_remote_class (domain, obj, klass, error);
6684 MONO_HANDLE_ASSIGN (result, obj);
6687 #endif /* DISABLE_REMOTING */
6693 * mono_object_castclass_mbyref:
6695 * @klass: a pointer to a class
6697 * Returns: @obj if @obj is derived from @klass, returns NULL otherwise.
6700 mono_object_castclass_mbyref (MonoObject *obj_raw, MonoClass *klass)
6702 MONO_REQ_GC_UNSAFE_MODE;
6703 HANDLE_FUNCTION_ENTER ();
6705 MONO_HANDLE_DCL (MonoObject, obj);
6706 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6707 if (MONO_HANDLE_IS_NULL (obj))
6709 MONO_HANDLE_ASSIGN (result, mono_object_handle_isinst_mbyref (obj, klass, &error));
6710 mono_error_cleanup (&error);
6712 HANDLE_FUNCTION_RETURN_OBJ (result);
6716 MonoDomain *orig_domain;
6722 str_lookup (MonoDomain *domain, gpointer user_data)
6724 MONO_REQ_GC_UNSAFE_MODE;
6726 LDStrInfo *info = (LDStrInfo *)user_data;
6727 if (info->res || domain == info->orig_domain)
6729 info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
6733 mono_string_get_pinned (MonoString *str, MonoError *error)
6735 MONO_REQ_GC_UNSAFE_MODE;
6737 mono_error_init (error);
6739 /* We only need to make a pinned version of a string if this is a moving GC */
6740 if (!mono_gc_is_moving ())
6744 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
6745 news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
6747 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
6748 news->length = mono_string_length (str);
6750 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6756 mono_string_is_interned_lookup (MonoString *str, int insert, MonoError *error)
6758 MONO_REQ_GC_UNSAFE_MODE;
6760 MonoGHashTable *ldstr_table;
6761 MonoString *s, *res;
6764 mono_error_init (error);
6766 domain = ((MonoObject *)str)->vtable->domain;
6767 ldstr_table = domain->ldstr_table;
6769 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6775 /* Allocate outside the lock */
6777 s = mono_string_get_pinned (str, error);
6778 return_val_if_nok (error, NULL);
6781 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6786 mono_g_hash_table_insert (ldstr_table, s, s);
6791 LDStrInfo ldstr_info;
6792 ldstr_info.orig_domain = domain;
6793 ldstr_info.ins = str;
6794 ldstr_info.res = NULL;
6796 mono_domain_foreach (str_lookup, &ldstr_info);
6797 if (ldstr_info.res) {
6799 * the string was already interned in some other domain:
6800 * intern it in the current one as well.
6802 mono_g_hash_table_insert (ldstr_table, str, str);
6812 * mono_string_is_interned:
6813 * @o: String to probe
6815 * Returns whether the string has been interned.
6818 mono_string_is_interned (MonoString *o)
6821 MonoString *result = mono_string_is_interned_lookup (o, FALSE, &error);
6822 /* This function does not fail. */
6823 mono_error_assert_ok (&error);
6828 * mono_string_intern:
6829 * @o: String to intern
6831 * Interns the string passed.
6832 * Returns: The interned string.
6835 mono_string_intern (MonoString *str)
6838 MonoString *result = mono_string_intern_checked (str, &error);
6839 mono_error_assert_ok (&error);
6844 * mono_string_intern_checked:
6845 * @o: String to intern
6846 * @error: set on error.
6848 * Interns the string passed.
6849 * Returns: The interned string. On failure returns NULL and sets @error
6852 mono_string_intern_checked (MonoString *str, MonoError *error)
6854 MONO_REQ_GC_UNSAFE_MODE;
6856 mono_error_init (error);
6858 return mono_string_is_interned_lookup (str, TRUE, error);
6863 * @domain: the domain where the string will be used.
6864 * @image: a metadata context
6865 * @idx: index into the user string table.
6867 * Implementation for the ldstr opcode.
6868 * Returns: a loaded string from the @image/@idx combination.
6871 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
6874 MonoString *result = mono_ldstr_checked (domain, image, idx, &error);
6875 mono_error_cleanup (&error);
6880 * mono_ldstr_checked:
6881 * @domain: the domain where the string will be used.
6882 * @image: a metadata context
6883 * @idx: index into the user string table.
6884 * @error: set on error.
6886 * Implementation for the ldstr opcode.
6887 * Returns: a loaded string from the @image/@idx combination.
6888 * On failure returns NULL and sets @error.
6891 mono_ldstr_checked (MonoDomain *domain, MonoImage *image, guint32 idx, MonoError *error)
6893 MONO_REQ_GC_UNSAFE_MODE;
6894 mono_error_init (error);
6896 if (image->dynamic) {
6897 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL, error);
6900 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6901 return NULL; /*FIXME we should probably be raising an exception here*/
6902 MonoString *str = mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx), error);
6908 * mono_ldstr_metadata_sig
6909 * @domain: the domain for the string
6910 * @sig: the signature of a metadata string
6911 * @error: set on error
6913 * Returns: a MonoString for a string stored in the metadata. On
6914 * failure returns NULL and sets @error.
6917 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error)
6919 MONO_REQ_GC_UNSAFE_MODE;
6921 mono_error_init (error);
6922 const char *str = sig;
6923 MonoString *o, *interned;
6926 len2 = mono_metadata_decode_blob_size (str, &str);
6929 o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, error);
6930 return_val_if_nok (error, NULL);
6931 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
6934 guint16 *p2 = (guint16*)mono_string_chars (o);
6935 for (i = 0; i < len2; ++i) {
6936 *p2 = GUINT16_FROM_LE (*p2);
6942 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6945 return interned; /* o will get garbage collected */
6947 o = mono_string_get_pinned (o, error);
6950 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6952 mono_g_hash_table_insert (domain->ldstr_table, o, o);
6964 * Same as mono_ldstr, but return a NULL terminated utf8 string instead
6968 mono_ldstr_utf8 (MonoImage *image, guint32 idx, MonoError *error)
6974 GError *gerror = NULL;
6976 mono_error_init (error);
6978 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6979 return NULL; /*FIXME we should probably be raising an exception here*/
6980 str = mono_metadata_user_string (image, idx);
6982 len2 = mono_metadata_decode_blob_size (str, &str);
6985 as = g_utf16_to_utf8 ((guint16*)str, len2, NULL, &written, &gerror);
6987 mono_error_set_argument (error, "string", "%s", gerror->message);
6988 g_error_free (gerror);
6991 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6992 if (len2 > written) {
6993 /* allocate the total length and copy the part of the string that has been converted */
6994 char *as2 = (char *)g_malloc0 (len2);
6995 memcpy (as2, as, written);
7004 * mono_string_to_utf8:
7005 * @s: a System.String
7007 * Returns the UTF8 representation for @s.
7008 * The resulting buffer needs to be freed with mono_free().
7010 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
7013 mono_string_to_utf8 (MonoString *s)
7015 MONO_REQ_GC_UNSAFE_MODE;
7018 char *result = mono_string_to_utf8_checked (s, &error);
7020 if (!is_ok (&error)) {
7021 mono_error_cleanup (&error);
7028 * mono_string_to_utf8_checked:
7029 * @s: a System.String
7030 * @error: a MonoError.
7032 * Converts a MonoString to its UTF8 representation. May fail; check
7033 * @error to determine whether the conversion was successful.
7034 * The resulting buffer should be freed with mono_free().
7037 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
7039 MONO_REQ_GC_UNSAFE_MODE;
7043 GError *gerror = NULL;
7045 mono_error_init (error);
7051 return g_strdup ("");
7053 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
7055 mono_error_set_argument (error, "string", "%s", gerror->message);
7056 g_error_free (gerror);
7059 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
7060 if (s->length > written) {
7061 /* allocate the total length and copy the part of the string that has been converted */
7062 char *as2 = (char *)g_malloc0 (s->length);
7063 memcpy (as2, as, written);
7072 mono_string_handle_to_utf8 (MonoStringHandle s, MonoError *error)
7074 return mono_string_to_utf8_checked (MONO_HANDLE_RAW (s), error);
7078 * mono_string_to_utf8_ignore:
7081 * Converts a MonoString to its UTF8 representation. Will ignore
7082 * invalid surrogate pairs.
7083 * The resulting buffer should be freed with mono_free().
7087 mono_string_to_utf8_ignore (MonoString *s)
7089 MONO_REQ_GC_UNSAFE_MODE;
7098 return g_strdup ("");
7100 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
7102 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
7103 if (s->length > written) {
7104 /* allocate the total length and copy the part of the string that has been converted */
7105 char *as2 = (char *)g_malloc0 (s->length);
7106 memcpy (as2, as, written);
7115 * mono_string_to_utf8_image_ignore:
7116 * @s: a System.String
7118 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
7121 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
7123 MONO_REQ_GC_UNSAFE_MODE;
7125 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
7129 * mono_string_to_utf8_mp_ignore:
7130 * @s: a System.String
7132 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
7135 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
7137 MONO_REQ_GC_UNSAFE_MODE;
7139 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
7144 * mono_string_to_utf16:
7147 * Return an null-terminated array of the utf-16 chars
7148 * contained in @s. The result must be freed with g_free().
7149 * This is a temporary helper until our string implementation
7150 * is reworked to always include the null terminating char.
7153 mono_string_to_utf16 (MonoString *s)
7155 MONO_REQ_GC_UNSAFE_MODE;
7162 as = (char *)g_malloc ((s->length * 2) + 2);
7163 as [(s->length * 2)] = '\0';
7164 as [(s->length * 2) + 1] = '\0';
7167 return (gunichar2 *)(as);
7170 memcpy (as, mono_string_chars(s), s->length * 2);
7171 return (gunichar2 *)(as);
7175 * mono_string_to_utf32:
7178 * Return an null-terminated array of the UTF-32 (UCS-4) chars
7179 * contained in @s. The result must be freed with g_free().
7182 mono_string_to_utf32 (MonoString *s)
7184 MONO_REQ_GC_UNSAFE_MODE;
7186 mono_unichar4 *utf32_output = NULL;
7187 GError *error = NULL;
7188 glong items_written;
7193 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
7196 g_error_free (error);
7198 return utf32_output;
7202 * mono_string_from_utf16:
7203 * @data: the UTF16 string (LPWSTR) to convert
7205 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
7207 * Returns: a MonoString.
7210 mono_string_from_utf16 (gunichar2 *data)
7213 MonoString *result = mono_string_from_utf16_checked (data, &error);
7214 mono_error_cleanup (&error);
7219 * mono_string_from_utf16_checked:
7220 * @data: the UTF16 string (LPWSTR) to convert
7221 * @error: set on error
7223 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
7225 * Returns: a MonoString. On failure sets @error and returns NULL.
7228 mono_string_from_utf16_checked (gunichar2 *data, MonoError *error)
7231 MONO_REQ_GC_UNSAFE_MODE;
7233 mono_error_init (error);
7234 MonoDomain *domain = mono_domain_get ();
7240 while (data [len]) len++;
7242 return mono_string_new_utf16_checked (domain, data, len, error);
7246 * mono_string_from_utf32:
7247 * @data: the UTF32 string (LPWSTR) to convert
7249 * Converts a UTF32 (UCS-4)to a MonoString.
7251 * Returns: a MonoString.
7254 mono_string_from_utf32 (mono_unichar4 *data)
7257 MonoString *result = mono_string_from_utf32_checked (data, &error);
7258 mono_error_cleanup (&error);
7263 * mono_string_from_utf32_checked:
7264 * @data: the UTF32 string (LPWSTR) to convert
7265 * @error: set on error
7267 * Converts a UTF32 (UCS-4)to a MonoString.
7269 * Returns: a MonoString. On failure returns NULL and sets @error.
7272 mono_string_from_utf32_checked (mono_unichar4 *data, MonoError *error)
7274 MONO_REQ_GC_UNSAFE_MODE;
7276 mono_error_init (error);
7277 MonoString* result = NULL;
7278 mono_unichar2 *utf16_output = NULL;
7279 GError *gerror = NULL;
7280 glong items_written;
7286 while (data [len]) len++;
7288 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &gerror);
7291 g_error_free (gerror);
7293 result = mono_string_from_utf16_checked (utf16_output, error);
7294 g_free (utf16_output);
7299 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
7301 MONO_REQ_GC_UNSAFE_MODE;
7308 r = mono_string_to_utf8_ignore (s);
7310 r = mono_string_to_utf8_checked (s, error);
7311 if (!mono_error_ok (error))
7318 len = strlen (r) + 1;
7320 mp_s = (char *)mono_mempool_alloc (mp, len);
7322 mp_s = (char *)mono_image_alloc (image, len);
7324 memcpy (mp_s, r, len);
7332 * mono_string_to_utf8_image:
7333 * @s: a System.String
7335 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
7338 mono_string_to_utf8_image (MonoImage *image, MonoStringHandle s, MonoError *error)
7340 MONO_REQ_GC_UNSAFE_MODE;
7342 return mono_string_to_utf8_internal (NULL, image, MONO_HANDLE_RAW (s), FALSE, error); /* FIXME pin the string */
7346 * mono_string_to_utf8_mp:
7347 * @s: a System.String
7349 * Same as mono_string_to_utf8, but allocate the string from a mempool.
7352 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
7354 MONO_REQ_GC_UNSAFE_MODE;
7356 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
7360 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
7363 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
7365 eh_callbacks = *cbs;
7368 MonoRuntimeExceptionHandlingCallbacks *
7369 mono_get_eh_callbacks (void)
7371 return &eh_callbacks;
7375 * mono_raise_exception:
7376 * @ex: exception object
7378 * Signal the runtime that the exception @ex has been raised in unmanaged code.
7381 mono_raise_exception (MonoException *ex)
7383 MONO_REQ_GC_UNSAFE_MODE;
7386 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
7387 * that will cause gcc to omit the function epilog, causing problems when
7388 * the JIT tries to walk the stack, since the return address on the stack
7389 * will point into the next function in the executable, not this one.
7391 eh_callbacks.mono_raise_exception (ex);
7395 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
7397 MONO_REQ_GC_UNSAFE_MODE;
7399 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
7403 * mono_wait_handle_new:
7404 * @domain: Domain where the object will be created
7405 * @handle: Handle for the wait handle
7406 * @error: set on error.
7408 * Returns: A new MonoWaitHandle created in the given domain for the
7409 * given handle. On failure returns NULL and sets @rror.
7412 mono_wait_handle_new (MonoDomain *domain, HANDLE handle, MonoError *error)
7414 MONO_REQ_GC_UNSAFE_MODE;
7416 MonoWaitHandle *res;
7417 gpointer params [1];
7418 static MonoMethod *handle_set;
7420 mono_error_init (error);
7421 res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, error);
7422 return_val_if_nok (error, NULL);
7424 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
7426 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
7428 params [0] = &handle;
7430 mono_runtime_invoke_checked (handle_set, res, params, error);
7435 mono_wait_handle_get_handle (MonoWaitHandle *handle)
7437 MONO_REQ_GC_UNSAFE_MODE;
7439 static MonoClassField *f_safe_handle = NULL;
7442 if (!f_safe_handle) {
7443 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safeWaitHandle");
7444 g_assert (f_safe_handle);
7447 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
7453 mono_runtime_capture_context (MonoDomain *domain, MonoError *error)
7455 MONO_REQ_GC_UNSAFE_MODE;
7457 RuntimeInvokeFunction runtime_invoke;
7459 mono_error_init (error);
7461 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
7462 MonoMethod *method = mono_get_context_capture_method ();
7463 MonoMethod *wrapper;
7466 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
7467 domain->capture_context_runtime_invoke = mono_compile_method_checked (wrapper, error);
7468 return_val_if_nok (error, NULL);
7469 domain->capture_context_method = mono_compile_method_checked (method, error);
7470 return_val_if_nok (error, NULL);
7473 runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
7475 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
7478 * mono_async_result_new:
7479 * @domain:domain where the object will be created.
7480 * @handle: wait handle.
7481 * @state: state to pass to AsyncResult
7482 * @data: C closure data.
7483 * @error: set on error.
7485 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
7486 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
7487 * On failure returns NULL and sets @error.
7491 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data, MonoError *error)
7493 MONO_REQ_GC_UNSAFE_MODE;
7495 mono_error_init (error);
7496 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, error);
7497 return_val_if_nok (error, NULL);
7498 MonoObject *context = mono_runtime_capture_context (domain, error);
7499 return_val_if_nok (error, NULL);
7500 /* we must capture the execution context from the original thread */
7502 MONO_OBJECT_SETREF (res, execution_context, context);
7503 /* note: result may be null if the flow is suppressed */
7506 res->data = (void **)data;
7507 MONO_OBJECT_SETREF (res, object_data, object_data);
7508 MONO_OBJECT_SETREF (res, async_state, state);
7509 MonoWaitHandle *wait_handle = mono_wait_handle_new (domain, handle, error);
7510 return_val_if_nok (error, NULL);
7512 MONO_OBJECT_SETREF (res, handle, (MonoObject *) wait_handle);
7514 res->sync_completed = FALSE;
7515 res->completed = FALSE;
7521 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
7523 MONO_REQ_GC_UNSAFE_MODE;
7530 g_assert (ares->async_delegate);
7532 ac = (MonoAsyncCall*) ares->object_data;
7534 res = mono_runtime_delegate_invoke_checked (ares->async_delegate, (void**) &ares->async_state, &error);
7535 if (mono_error_set_pending_exception (&error))
7538 gpointer wait_event = NULL;
7540 ac->msg->exc = NULL;
7542 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args, &error);
7544 /* The exit side of the invoke must not be aborted as it would leave the runtime in an undefined state */
7545 mono_threads_begin_abort_protected_block ();
7547 if (!ac->msg->exc) {
7548 MonoException *ex = mono_error_convert_to_exception (&error);
7549 ac->msg->exc = (MonoObject *)ex;
7551 mono_error_cleanup (&error);
7554 MONO_OBJECT_SETREF (ac, res, res);
7556 mono_monitor_enter ((MonoObject*) ares);
7557 ares->completed = 1;
7559 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
7560 mono_monitor_exit ((MonoObject*) ares);
7562 if (wait_event != NULL)
7563 mono_w32event_set (wait_event);
7565 mono_error_init (&error); //the else branch would leave it in an undefined state
7567 mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
7569 mono_threads_end_abort_protected_block ();
7571 if (mono_error_set_pending_exception (&error))
7579 mono_message_init (MonoDomain *domain,
7580 MonoMethodMessage *this_obj,
7581 MonoReflectionMethod *method,
7582 MonoArray *out_args,
7585 MONO_REQ_GC_UNSAFE_MODE;
7587 static MonoMethod *init_message_method = NULL;
7589 if (!init_message_method) {
7590 init_message_method = mono_class_get_method_from_name (mono_defaults.mono_method_message_class, "InitMessage", 2);
7591 g_assert (init_message_method != NULL);
7594 mono_error_init (error);
7595 /* FIXME set domain instead? */
7596 g_assert (domain == mono_domain_get ());
7603 mono_runtime_invoke_checked (init_message_method, this_obj, args, error);
7604 return is_ok (error);
7607 #ifndef DISABLE_REMOTING
7609 * mono_remoting_invoke:
7610 * @real_proxy: pointer to a RealProxy object
7611 * @msg: The MonoMethodMessage to execute
7612 * @exc: used to store exceptions
7613 * @out_args: used to store output arguments
7615 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
7616 * IMessage interface and it is not trivial to extract results from there. So
7617 * we call an helper method PrivateInvoke instead of calling
7618 * RealProxy::Invoke() directly.
7620 * Returns: the result object.
7623 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, MonoObject **exc, MonoArray **out_args, MonoError *error)
7625 MONO_REQ_GC_UNSAFE_MODE;
7628 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
7633 mono_error_init (error);
7635 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
7638 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
7640 mono_error_set_not_supported (error, "Linked away.");
7643 real_proxy->vtable->domain->private_invoke_method = im;
7646 pa [0] = real_proxy;
7651 o = mono_runtime_try_invoke (im, NULL, pa, exc, error);
7652 return_val_if_nok (error, NULL);
7659 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
7660 MonoObject **exc, MonoArray **out_args, MonoError *error)
7662 MONO_REQ_GC_UNSAFE_MODE;
7664 static MonoClass *object_array_klass;
7665 mono_error_init (error);
7669 MonoMethodSignature *sig;
7671 int i, j, outarg_count = 0;
7673 #ifndef DISABLE_REMOTING
7674 if (target && mono_object_is_transparent_proxy (target)) {
7675 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
7676 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7677 target = tp->rp->unwrapped_server;
7679 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args, error);
7684 domain = mono_domain_get ();
7685 method = msg->method->method;
7686 sig = mono_method_signature (method);
7688 for (i = 0; i < sig->param_count; i++) {
7689 if (sig->params [i]->byref)
7693 if (!object_array_klass) {
7696 klass = mono_array_class_get (mono_defaults.object_class, 1);
7699 mono_memory_barrier ();
7700 object_array_klass = klass;
7703 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, error);
7704 return_val_if_nok (error, NULL);
7706 mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
7709 MonoObject *ret = mono_runtime_try_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc, error);
7710 return_val_if_nok (error, NULL);
7712 for (i = 0, j = 0; i < sig->param_count; i++) {
7713 if (sig->params [i]->byref) {
7715 arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
7716 mono_array_setref (*out_args, j, arg);
7725 * prepare_to_string_method:
7727 * @target: Set to @obj or unboxed value if a valuetype
7729 * Returns: the ToString override for @obj. If @obj is a valuetype, @target is unboxed otherwise it's @obj.
7732 prepare_to_string_method (MonoObject *obj, void **target)
7734 MONO_REQ_GC_UNSAFE_MODE;
7736 static MonoMethod *to_string = NULL;
7744 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
7746 method = mono_object_get_virtual_method (obj, to_string);
7748 // Unbox value type if needed
7749 if (mono_class_is_valuetype (mono_method_get_class (method))) {
7750 *target = mono_object_unbox (obj);
7756 * mono_object_to_string:
7758 * @exc: Any exception thrown by ToString (). May be NULL.
7760 * Returns: the result of calling ToString () on an object.
7763 mono_object_to_string (MonoObject *obj, MonoObject **exc)
7766 MonoString *s = NULL;
7768 MonoMethod *method = prepare_to_string_method (obj, &target);
7770 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
7771 if (*exc == NULL && !mono_error_ok (&error))
7772 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
7774 mono_error_cleanup (&error);
7776 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
7777 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
7784 * mono_object_to_string_checked:
7786 * @error: Set on error.
7788 * Returns: the result of calling ToString () on an object. If the
7789 * method cannot be invoked or if it raises an exception, sets @error
7793 mono_object_to_string_checked (MonoObject *obj, MonoError *error)
7795 mono_error_init (error);
7797 MonoMethod *method = prepare_to_string_method (obj, &target);
7798 return (MonoString*) mono_runtime_invoke_checked (method, target, NULL, error);
7802 * mono_object_try_to_string:
7804 * @exc: Any exception thrown by ToString (). Must not be NULL.
7805 * @error: Set if method cannot be invoked.
7807 * Returns: the result of calling ToString () on an object. If the
7808 * method cannot be invoked sets @error, if it raises an exception sets @exc,
7812 mono_object_try_to_string (MonoObject *obj, MonoObject **exc, MonoError *error)
7815 mono_error_init (error);
7817 MonoMethod *method = prepare_to_string_method (obj, &target);
7818 return (MonoString*) mono_runtime_try_invoke (method, target, NULL, exc, error);
7824 get_native_backtrace (MonoException *exc_raw)
7826 HANDLE_FUNCTION_ENTER ();
7827 MONO_HANDLE_DCL(MonoException, exc);
7828 char * trace = mono_exception_handle_get_native_backtrace (exc);
7829 HANDLE_FUNCTION_RETURN_VAL (trace);
7833 * mono_print_unhandled_exception:
7834 * @exc: The exception
7836 * Prints the unhandled exception.
7839 mono_print_unhandled_exception (MonoObject *exc)
7841 MONO_REQ_GC_UNSAFE_MODE;
7844 char *message = (char*)"";
7845 gboolean free_message = FALSE;
7848 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
7849 message = g_strdup ("OutOfMemoryException");
7850 free_message = TRUE;
7851 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
7852 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
7853 free_message = TRUE;
7856 if (((MonoException*)exc)->native_trace_ips) {
7857 message = get_native_backtrace ((MonoException*)exc);
7858 free_message = TRUE;
7860 MonoObject *other_exc = NULL;
7861 str = mono_object_try_to_string (exc, &other_exc, &error);
7862 if (other_exc == NULL && !is_ok (&error))
7863 other_exc = (MonoObject*)mono_error_convert_to_exception (&error);
7865 mono_error_cleanup (&error);
7867 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
7868 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
7870 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
7871 original_backtrace, nested_backtrace);
7873 g_free (original_backtrace);
7874 g_free (nested_backtrace);
7875 free_message = TRUE;
7877 message = mono_string_to_utf8_checked (str, &error);
7878 if (!mono_error_ok (&error)) {
7879 mono_error_cleanup (&error);
7880 message = (char *) "";
7882 free_message = TRUE;
7889 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
7890 * exc->vtable->klass->name, message);
7892 g_printerr ("\nUnhandled Exception:\n%s\n", message);
7899 * mono_delegate_ctor_with_method:
7900 * @this: pointer to an uninitialized delegate object
7901 * @target: target object
7902 * @addr: pointer to native code
7904 * @error: set on error.
7906 * Initialize a delegate and sets a specific method, not the one
7907 * associated with addr. This is useful when sharing generic code.
7908 * In that case addr will most probably not be associated with the
7909 * correct instantiation of the method.
7910 * On failure returns FALSE and sets @error.
7913 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method, MonoError *error)
7915 MONO_REQ_GC_UNSAFE_MODE;
7917 mono_error_init (error);
7918 MonoDelegate *delegate = (MonoDelegate *)this_obj;
7920 g_assert (this_obj);
7923 g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
7926 delegate->method = method;
7928 mono_stats.delegate_creations++;
7930 #ifndef DISABLE_REMOTING
7931 if (target && mono_object_is_transparent_proxy (target)) {
7933 method = mono_marshal_get_remoting_invoke (method);
7934 delegate->method_ptr = mono_compile_method_checked (method, error);
7935 return_val_if_nok (error, FALSE);
7936 MONO_OBJECT_SETREF (delegate, target, target);
7940 delegate->method_ptr = addr;
7941 MONO_OBJECT_SETREF (delegate, target, target);
7944 delegate->invoke_impl = callbacks.create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
7945 if (callbacks.init_delegate)
7946 callbacks.init_delegate (delegate);
7951 * mono_delegate_ctor:
7952 * @this: pointer to an uninitialized delegate object
7953 * @target: target object
7954 * @addr: pointer to native code
7955 * @error: set on error.
7957 * This is used to initialize a delegate.
7958 * On failure returns FALSE and sets @error.
7961 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoError *error)
7963 MONO_REQ_GC_UNSAFE_MODE;
7965 mono_error_init (error);
7966 MonoDomain *domain = mono_domain_get ();
7968 MonoMethod *method = NULL;
7972 ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
7974 if (!ji && domain != mono_get_root_domain ())
7975 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
7977 method = mono_jit_info_get_method (ji);
7978 g_assert (!mono_class_is_gtd (method->klass));
7981 return mono_delegate_ctor_with_method (this_obj, target, addr, method, error);
7985 * mono_method_call_message_new:
7986 * @method: method to encapsulate
7987 * @params: parameters to the method
7988 * @invoke: optional, delegate invoke.
7989 * @cb: async callback delegate.
7990 * @state: state passed to the async callback.
7991 * @error: set on error.
7993 * Translates arguments pointers into a MonoMethodMessage.
7994 * On failure returns NULL and sets @error.
7997 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
7998 MonoDelegate **cb, MonoObject **state, MonoError *error)
8000 MONO_REQ_GC_UNSAFE_MODE;
8002 mono_error_init (error);
8004 MonoDomain *domain = mono_domain_get ();
8005 MonoMethodSignature *sig = mono_method_signature (method);
8006 MonoMethodMessage *msg;
8009 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8010 return_val_if_nok (error, NULL);
8013 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, error);
8014 return_val_if_nok (error, NULL);
8015 mono_message_init (domain, msg, rm, NULL, error);
8016 return_val_if_nok (error, NULL);
8017 count = sig->param_count - 2;
8019 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
8020 return_val_if_nok (error, NULL);
8021 mono_message_init (domain, msg, rm, NULL, error);
8022 return_val_if_nok (error, NULL);
8023 count = sig->param_count;
8026 for (i = 0; i < count; i++) {
8031 if (sig->params [i]->byref)
8032 vpos = *((gpointer *)params [i]);
8036 klass = mono_class_from_mono_type (sig->params [i]);
8038 if (klass->valuetype) {
8039 arg = mono_value_box_checked (domain, klass, vpos, error);
8040 return_val_if_nok (error, NULL);
8042 arg = *((MonoObject **)vpos);
8044 mono_array_setref (msg->args, i, arg);
8047 if (cb != NULL && state != NULL) {
8048 *cb = *((MonoDelegate **)params [i]);
8050 *state = *((MonoObject **)params [i]);
8057 * mono_method_return_message_restore:
8059 * Restore results from message based processing back to arguments pointers
8062 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args, MonoError *error)
8064 MONO_REQ_GC_UNSAFE_MODE;
8066 mono_error_init (error);
8068 MonoMethodSignature *sig = mono_method_signature (method);
8069 int i, j, type, size, out_len;
8071 if (out_args == NULL)
8073 out_len = mono_array_length (out_args);
8077 for (i = 0, j = 0; i < sig->param_count; i++) {
8078 MonoType *pt = sig->params [i];
8083 mono_error_set_execution_engine (error, "The proxy call returned an incorrect number of output arguments");
8087 arg = (char *)mono_array_get (out_args, gpointer, j);
8090 g_assert (type != MONO_TYPE_VOID);
8092 if (MONO_TYPE_IS_REFERENCE (pt)) {
8093 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
8096 MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
8097 size = mono_class_value_size (klass, NULL);
8098 if (klass->has_references)
8099 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
8101 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
8103 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
8104 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
8113 #ifndef DISABLE_REMOTING
8116 * mono_load_remote_field:
8117 * @this: pointer to an object
8118 * @klass: klass of the object containing @field
8119 * @field: the field to load
8120 * @res: a storage to store the result
8122 * This method is called by the runtime on attempts to load fields of
8123 * transparent proxy objects. @this points to such TP, @klass is the class of
8124 * the object containing @field. @res is a storage location which can be
8125 * used to store the result.
8127 * Returns: an address pointing to the value of field.
8130 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
8133 gpointer result = mono_load_remote_field_checked (this_obj, klass, field, res, &error);
8134 mono_error_cleanup (&error);
8139 * mono_load_remote_field_checked:
8140 * @this: pointer to an object
8141 * @klass: klass of the object containing @field
8142 * @field: the field to load
8143 * @res: a storage to store the result
8144 * @error: set on error
8146 * This method is called by the runtime on attempts to load fields of
8147 * transparent proxy objects. @this points to such TP, @klass is the class of
8148 * the object containing @field. @res is a storage location which can be
8149 * used to store the result.
8151 * Returns: an address pointing to the value of field. On failure returns NULL and sets @error.
8154 mono_load_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res, MonoError *error)
8156 MONO_REQ_GC_UNSAFE_MODE;
8158 static MonoMethod *getter = NULL;
8160 mono_error_init (error);
8162 MonoDomain *domain = mono_domain_get ();
8163 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8164 MonoClass *field_class;
8165 MonoMethodMessage *msg;
8166 MonoArray *out_args;
8170 g_assert (mono_object_is_transparent_proxy (this_obj));
8171 g_assert (res != NULL);
8173 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8174 mono_field_get_value (tp->rp->unwrapped_server, field, res);
8179 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
8181 mono_error_set_not_supported (error, "Linked away.");
8186 field_class = mono_class_from_mono_type (field->type);
8188 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8189 return_val_if_nok (error, NULL);
8190 out_args = mono_array_new_checked (domain, mono_defaults.object_class, 1, error);
8191 return_val_if_nok (error, NULL);
8192 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, error);
8193 return_val_if_nok (error, NULL);
8194 mono_message_init (domain, msg, rm, out_args, error);
8195 return_val_if_nok (error, NULL);
8197 full_name = mono_type_get_full_name (klass);
8198 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
8199 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
8202 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8203 return_val_if_nok (error, NULL);
8206 mono_error_set_exception_instance (error, (MonoException *)exc);
8210 if (mono_array_length (out_args) == 0)
8213 mono_gc_wbarrier_generic_store (res, mono_array_get (out_args, MonoObject *, 0));
8215 if (field_class->valuetype) {
8216 return ((char *)*res) + sizeof (MonoObject);
8222 * mono_load_remote_field_new:
8227 * Missing documentation.
8230 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
8234 MonoObject *result = mono_load_remote_field_new_checked (this_obj, klass, field, &error);
8235 mono_error_cleanup (&error);
8240 * mono_load_remote_field_new_checked:
8241 * @this: pointer to an object
8242 * @klass: klass of the object containing @field
8243 * @field: the field to load
8244 * @error: set on error.
8246 * This method is called by the runtime on attempts to load fields of
8247 * transparent proxy objects. @this points to such TP, @klass is the class of
8248 * the object containing @field.
8250 * Returns: a freshly allocated object containing the value of the field. On failure returns NULL and sets @error.
8253 mono_load_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoError *error)
8255 MONO_REQ_GC_UNSAFE_MODE;
8257 mono_error_init (error);
8259 static MonoMethod *tp_load = NULL;
8261 g_assert (mono_object_is_transparent_proxy (this_obj));
8264 tp_load = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "LoadRemoteFieldNew", -1);
8266 mono_error_set_not_supported (error, "Linked away.");
8271 /* MonoType *type = mono_class_get_type (klass); */
8277 return mono_runtime_invoke_checked (tp_load, this_obj, args, error);
8281 * mono_store_remote_field:
8282 * @this_obj: pointer to an object
8283 * @klass: klass of the object containing @field
8284 * @field: the field to load
8285 * @val: the value/object to store
8287 * This method is called by the runtime on attempts to store fields of
8288 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
8289 * the object containing @field. @val is the new value to store in @field.
8292 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
8295 (void) mono_store_remote_field_checked (this_obj, klass, field, val, &error);
8296 mono_error_cleanup (&error);
8300 * mono_store_remote_field_checked:
8301 * @this_obj: pointer to an object
8302 * @klass: klass of the object containing @field
8303 * @field: the field to load
8304 * @val: the value/object to store
8305 * @error: set on error
8307 * This method is called by the runtime on attempts to store fields of
8308 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
8309 * the object containing @field. @val is the new value to store in @field.
8311 * Returns: on success returns TRUE, on failure returns FALSE and sets @error.
8314 mono_store_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val, MonoError *error)
8317 MONO_REQ_GC_UNSAFE_MODE;
8319 mono_error_init (error);
8321 MonoDomain *domain = mono_domain_get ();
8322 MonoClass *field_class;
8325 g_assert (mono_object_is_transparent_proxy (this_obj));
8327 field_class = mono_class_from_mono_type (field->type);
8329 if (field_class->valuetype) {
8330 arg = mono_value_box_checked (domain, field_class, val, error);
8331 return_val_if_nok (error, FALSE);
8333 arg = *((MonoObject**)val);
8336 return mono_store_remote_field_new_checked (this_obj, klass, field, arg, error);
8340 * mono_store_remote_field_new:
8346 * Missing documentation
8349 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
8352 (void) mono_store_remote_field_new_checked (this_obj, klass, field, arg, &error);
8353 mono_error_cleanup (&error);
8357 * mono_store_remote_field_new_checked:
8364 * Missing documentation
8367 mono_store_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg, MonoError *error)
8369 MONO_REQ_GC_UNSAFE_MODE;
8371 static MonoMethod *tp_store = NULL;
8373 mono_error_init (error);
8375 g_assert (mono_object_is_transparent_proxy (this_obj));
8378 tp_store = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "StoreRemoteField", -1);
8380 mono_error_set_not_supported (error, "Linked away.");
8390 mono_runtime_invoke_checked (tp_store, this_obj, args, error);
8391 return is_ok (error);
8396 * mono_create_ftnptr:
8398 * Given a function address, create a function descriptor for it.
8399 * This is only needed on some platforms.
8402 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
8404 return callbacks.create_ftnptr (domain, addr);
8408 * mono_get_addr_from_ftnptr:
8410 * Given a pointer to a function descriptor, return the function address.
8411 * This is only needed on some platforms.
8414 mono_get_addr_from_ftnptr (gpointer descr)
8416 return callbacks.get_addr_from_ftnptr (descr);
8420 * mono_string_chars:
8423 * Returns a pointer to the UCS16 characters stored in the MonoString
8426 mono_string_chars (MonoString *s)
8428 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
8434 * mono_string_length:
8437 * Returns the lenght in characters of the string
8440 mono_string_length (MonoString *s)
8442 MONO_REQ_GC_UNSAFE_MODE;
8448 * mono_string_handle_length:
8451 * Returns the lenght in characters of the string
8454 mono_string_handle_length (MonoStringHandle s)
8456 MONO_REQ_GC_UNSAFE_MODE;
8458 return MONO_HANDLE_GETVAL (s, length);
8463 * mono_array_length:
8464 * @array: a MonoArray*
8466 * Returns the total number of elements in the array. This works for
8467 * both vectors and multidimensional arrays.
8470 mono_array_length (MonoArray *array)
8472 MONO_REQ_GC_UNSAFE_MODE;
8474 return array->max_length;
8478 * mono_array_addr_with_size:
8479 * @array: a MonoArray*
8480 * @size: size of the array elements
8481 * @idx: index into the array
8483 * Use this function to obtain the address for the @idx item on the
8484 * @array containing elements of size @size.
8486 * This method performs no bounds checking or type checking.
8488 * Returns the address of the @idx element in the array.
8491 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
8493 MONO_REQ_GC_UNSAFE_MODE;
8495 return ((char*)(array)->vector) + size * idx;
8500 mono_glist_to_array (GList *list, MonoClass *eclass, MonoError *error)
8502 MonoDomain *domain = mono_domain_get ();
8506 mono_error_init (error);
8510 len = g_list_length (list);
8511 res = mono_array_new_checked (domain, eclass, len, error);
8512 return_val_if_nok (error, NULL);
8514 for (i = 0; list; list = list->next, i++)
8515 mono_array_set (res, gpointer, i, list->data);
8522 * The following section is purely to declare prototypes and
8523 * document the API, as these C files are processed by our
8529 * @array: array to alter
8530 * @element_type: A C type name, this macro will use the sizeof(type) to determine the element size
8531 * @index: index into the array
8532 * @value: value to set
8534 * Value Type version: This sets the @index's element of the @array
8535 * with elements of size sizeof(type) to the provided @value.
8537 * This macro does not attempt to perform type checking or bounds checking.
8539 * Use this to set value types in a `MonoArray`.
8541 void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
8546 * mono_array_setref:
8547 * @array: array to alter
8548 * @index: index into the array
8549 * @value: value to set
8551 * Reference Type version: This sets the @index's element of the
8552 * @array with elements of size sizeof(type) to the provided @value.
8554 * This macro does not attempt to perform type checking or bounds checking.
8556 * Use this to reference types in a `MonoArray`.
8558 void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
8564 * @array: array on which to operate on
8565 * @element_type: C element type (example: MonoString *, int, MonoObject *)
8566 * @index: index into the array
8568 * Use this macro to retrieve the @index element of an @array and
8569 * extract the value assuming that the elements of the array match
8570 * the provided type value.
8572 * This method can be used with both arrays holding value types and
8573 * reference types. For reference types, the @type parameter should
8574 * be a `MonoObject*` or any subclass of it, like `MonoString*`.
8576 * This macro does not attempt to perform type checking or bounds checking.
8578 * Returns: The element at the @index position in the @array.
8580 Type mono_array_get (MonoArray *array, Type element_type, uintptr_t index)