2 * object.c: Object creation for the Mono runtime
5 * Miguel de Icaza (miguel@ximian.com)
6 * Paolo Molaro (lupus@ximian.com)
8 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
9 * Copyright 2004-2011 Novell, Inc (http://www.novell.com)
10 * Copyright 2001 Xamarin Inc (http://www.xamarin.com)
11 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
20 #include <mono/metadata/mono-endian.h>
21 #include <mono/metadata/tabledefs.h>
22 #include <mono/metadata/tokentype.h>
23 #include <mono/metadata/loader.h>
24 #include <mono/metadata/object.h>
25 #include <mono/metadata/gc-internals.h>
26 #include <mono/metadata/exception.h>
27 #include <mono/metadata/exception-internals.h>
28 #include <mono/metadata/domain-internals.h>
29 #include "mono/metadata/metadata-internals.h"
30 #include "mono/metadata/class-internals.h"
31 #include <mono/metadata/assembly.h>
32 #include <mono/metadata/marshal.h>
33 #include "mono/metadata/debug-helpers.h"
34 #include "mono/metadata/marshal.h"
35 #include <mono/metadata/threads.h>
36 #include <mono/metadata/threads-types.h>
37 #include <mono/metadata/environment.h>
38 #include "mono/metadata/profiler-private.h"
39 #include "mono/metadata/security-manager.h"
40 #include "mono/metadata/mono-debug-debugger.h"
41 #include <mono/metadata/gc-internals.h>
42 #include <mono/metadata/verify-internals.h>
43 #include <mono/metadata/reflection-internals.h>
44 #include <mono/utils/strenc.h>
45 #include <mono/utils/mono-counters.h>
46 #include <mono/utils/mono-error-internals.h>
47 #include <mono/utils/mono-memory-model.h>
48 #include <mono/utils/checked-build.h>
49 #include <mono/utils/mono-threads.h>
50 #include "cominterop.h"
53 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error);
56 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error);
59 free_main_args (void);
62 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error);
64 /* Class lazy loading functions */
65 static GENERATE_GET_CLASS_WITH_CACHE (pointer, System.Reflection, Pointer)
66 static GENERATE_GET_CLASS_WITH_CACHE (remoting_services, System.Runtime.Remoting, RemotingServices)
67 static GENERATE_GET_CLASS_WITH_CACHE (unhandled_exception_event_args, System, UnhandledExceptionEventArgs)
68 static GENERATE_GET_CLASS_WITH_CACHE (sta_thread_attribute, System, STAThreadAttribute)
69 static GENERATE_GET_CLASS_WITH_CACHE (activation_services, System.Runtime.Remoting.Activation, ActivationServices)
72 #define ldstr_lock() mono_os_mutex_lock (&ldstr_section)
73 #define ldstr_unlock() mono_os_mutex_unlock (&ldstr_section)
74 static mono_mutex_t ldstr_section;
77 * mono_runtime_object_init:
78 * @this_obj: the object to initialize
80 * This function calls the zero-argument constructor (which must
81 * exist) for the given object.
84 mono_runtime_object_init (MonoObject *this_obj)
87 mono_runtime_object_init_checked (this_obj, &error);
88 mono_error_assert_ok (&error);
92 * mono_runtime_object_init_checked:
93 * @this_obj: the object to initialize
94 * @error: set on error.
96 * This function calls the zero-argument constructor (which must
97 * exist) for the given object and returns TRUE on success, or FALSE
98 * on error and sets @error.
101 mono_runtime_object_init_checked (MonoObject *this_obj, MonoError *error)
103 MONO_REQ_GC_UNSAFE_MODE;
105 MonoMethod *method = NULL;
106 MonoClass *klass = this_obj->vtable->klass;
108 mono_error_init (error);
109 method = mono_class_get_method_from_name (klass, ".ctor", 0);
111 g_error ("Could not lookup zero argument constructor for class %s", mono_type_get_full_name (klass));
113 if (method->klass->valuetype)
114 this_obj = (MonoObject *)mono_object_unbox (this_obj);
116 mono_runtime_invoke_checked (method, this_obj, NULL, error);
117 return is_ok (error);
120 /* The pseudo algorithm for type initialization from the spec
121 Note it doesn't say anything about domains - only threads.
123 2. If the type is initialized you are done.
124 2.1. If the type is not yet initialized, try to take an
126 2.2. If successful, record this thread as responsible for
127 initializing the type and proceed to step 2.3.
128 2.2.1. If not, see whether this thread or any thread
129 waiting for this thread to complete already holds the lock.
130 2.2.2. If so, return since blocking would create a deadlock. This thread
131 will now see an incompletely initialized state for the type,
132 but no deadlock will arise.
133 2.2.3 If not, block until the type is initialized then return.
134 2.3 Initialize the parent type and then all interfaces implemented
136 2.4 Execute the type initialization code for this type.
137 2.5 Mark the type as initialized, release the initialization lock,
138 awaken any threads waiting for this type to be initialized,
145 MonoNativeThreadId initializing_tid;
146 guint32 waiting_count;
148 MonoCoopMutex initialization_section;
149 } TypeInitializationLock;
151 /* for locking access to type_initialization_hash and blocked_thread_hash */
152 static MonoCoopMutex type_initialization_section;
155 mono_type_initialization_lock (void)
157 /* The critical sections protected by this lock in mono_runtime_class_init_full () can block */
158 mono_coop_mutex_lock (&type_initialization_section);
162 mono_type_initialization_unlock (void)
164 mono_coop_mutex_unlock (&type_initialization_section);
168 mono_type_init_lock (TypeInitializationLock *lock)
170 MONO_REQ_GC_NEUTRAL_MODE;
172 mono_coop_mutex_lock (&lock->initialization_section);
176 mono_type_init_unlock (TypeInitializationLock *lock)
178 mono_coop_mutex_unlock (&lock->initialization_section);
181 /* from vtable to lock */
182 static GHashTable *type_initialization_hash;
184 /* from thread id to thread id being waited on */
185 static GHashTable *blocked_thread_hash;
188 static MonoThread *main_thread;
190 /* Functions supplied by the runtime */
191 static MonoRuntimeCallbacks callbacks;
194 * mono_thread_set_main:
195 * @thread: thread to set as the main thread
197 * This function can be used to instruct the runtime to treat @thread
198 * as the main thread, ie, the thread that would normally execute the Main()
199 * method. This basically means that at the end of @thread, the runtime will
200 * wait for the existing foreground threads to quit and other such details.
203 mono_thread_set_main (MonoThread *thread)
205 MONO_REQ_GC_UNSAFE_MODE;
207 static gboolean registered = FALSE;
210 MONO_GC_REGISTER_ROOT_SINGLE (main_thread, MONO_ROOT_SOURCE_THREADING, "main thread object");
214 main_thread = thread;
218 mono_thread_get_main (void)
220 MONO_REQ_GC_UNSAFE_MODE;
226 mono_type_initialization_init (void)
228 mono_coop_mutex_init_recursive (&type_initialization_section);
229 type_initialization_hash = g_hash_table_new (NULL, NULL);
230 blocked_thread_hash = g_hash_table_new (NULL, NULL);
231 mono_os_mutex_init_recursive (&ldstr_section);
235 mono_type_initialization_cleanup (void)
238 /* This is causing race conditions with
239 * mono_release_type_locks
241 mono_coop_mutex_destroy (&type_initialization_section);
242 g_hash_table_destroy (type_initialization_hash);
243 type_initialization_hash = NULL;
245 mono_os_mutex_destroy (&ldstr_section);
246 g_hash_table_destroy (blocked_thread_hash);
247 blocked_thread_hash = NULL;
253 * get_type_init_exception_for_vtable:
255 * Return the stored type initialization exception for VTABLE.
257 static MonoException*
258 get_type_init_exception_for_vtable (MonoVTable *vtable)
260 MONO_REQ_GC_UNSAFE_MODE;
263 MonoDomain *domain = vtable->domain;
264 MonoClass *klass = vtable->klass;
268 if (!vtable->init_failed)
269 g_error ("Trying to get the init exception for a non-failed vtable of class %s", mono_type_get_full_name (klass));
272 * If the initializing thread was rudely aborted, the exception is not stored
276 mono_domain_lock (domain);
277 if (domain->type_init_exception_hash)
278 ex = (MonoException *)mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
279 mono_domain_unlock (domain);
282 if (klass->name_space && *klass->name_space)
283 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
285 full_name = g_strdup (klass->name);
286 ex = mono_get_exception_type_initialization_checked (full_name, NULL, &error);
288 return_val_if_nok (&error, NULL);
295 * mono_runtime_class_init:
296 * @vtable: vtable that needs to be initialized
298 * This routine calls the class constructor for @vtable.
301 mono_runtime_class_init (MonoVTable *vtable)
303 MONO_REQ_GC_UNSAFE_MODE;
306 mono_runtime_class_init_full (vtable, &error);
307 mono_error_assert_ok (&error);
311 * mono_runtime_class_init_full:
312 * @vtable that neeeds to be initialized
313 * @error set on error
315 * returns TRUE if class constructor .cctor has been initialized successfully, or FALSE otherwise and sets @error.
319 mono_runtime_class_init_full (MonoVTable *vtable, MonoError *error)
321 MONO_REQ_GC_UNSAFE_MODE;
323 MonoMethod *method = NULL;
326 MonoDomain *domain = vtable->domain;
327 TypeInitializationLock *lock;
328 MonoNativeThreadId tid;
329 int do_initialization = 0;
330 MonoDomain *last_domain = NULL;
332 mono_error_init (error);
334 if (vtable->initialized)
337 klass = vtable->klass;
339 if (!klass->image->checked_module_cctor) {
340 mono_image_check_for_module_cctor (klass->image);
341 if (klass->image->has_module_cctor) {
342 MonoClass *module_klass;
343 MonoVTable *module_vtable;
345 module_klass = mono_class_get_checked (klass->image, MONO_TOKEN_TYPE_DEF | 1, error);
350 module_vtable = mono_class_vtable_full (vtable->domain, module_klass, error);
353 if (!mono_runtime_class_init_full (module_vtable, error))
357 method = mono_class_get_cctor (klass);
359 vtable->initialized = 1;
363 tid = mono_native_thread_id_get ();
365 mono_type_initialization_lock ();
366 /* double check... */
367 if (vtable->initialized) {
368 mono_type_initialization_unlock ();
371 if (vtable->init_failed) {
372 mono_type_initialization_unlock ();
374 /* The type initialization already failed once, rethrow the same exception */
375 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
378 lock = (TypeInitializationLock *)g_hash_table_lookup (type_initialization_hash, vtable);
380 /* This thread will get to do the initialization */
381 if (mono_domain_get () != domain) {
382 /* Transfer into the target domain */
383 last_domain = mono_domain_get ();
384 if (!mono_domain_set (domain, FALSE)) {
385 vtable->initialized = 1;
386 mono_type_initialization_unlock ();
387 mono_error_set_exception_instance (error, mono_get_exception_appdomain_unloaded ());
391 lock = (TypeInitializationLock *)g_malloc (sizeof (TypeInitializationLock));
392 mono_coop_mutex_init_recursive (&lock->initialization_section);
393 lock->initializing_tid = tid;
394 lock->waiting_count = 1;
396 /* grab the vtable lock while this thread still owns type_initialization_section */
397 /* This is why type_initialization_lock needs to enter blocking mode */
398 mono_type_init_lock (lock);
399 g_hash_table_insert (type_initialization_hash, vtable, lock);
400 do_initialization = 1;
403 TypeInitializationLock *pending_lock;
405 if (mono_native_thread_id_equals (lock->initializing_tid, tid) || lock->done) {
406 mono_type_initialization_unlock ();
409 /* see if the thread doing the initialization is already blocked on this thread */
410 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (lock->initializing_tid));
411 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
412 if (mono_native_thread_id_equals (pending_lock->initializing_tid, tid)) {
413 if (!pending_lock->done) {
414 mono_type_initialization_unlock ();
417 /* the thread doing the initialization is blocked on this thread,
418 but on a lock that has already been freed. It just hasn't got
423 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (pending_lock->initializing_tid));
425 ++lock->waiting_count;
426 /* record the fact that we are waiting on the initializing thread */
427 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
429 mono_type_initialization_unlock ();
431 if (do_initialization) {
432 MonoException *exc = NULL;
433 mono_runtime_try_invoke (method, NULL, NULL, (MonoObject**) &exc, error);
434 if (exc != NULL && mono_error_ok (error)) {
435 mono_error_set_exception_instance (error, exc);
438 /* If the initialization failed, mark the class as unusable. */
439 /* Avoid infinite loops */
440 if (!(mono_error_ok(error) ||
441 (klass->image == mono_defaults.corlib &&
442 !strcmp (klass->name_space, "System") &&
443 !strcmp (klass->name, "TypeInitializationException")))) {
444 vtable->init_failed = 1;
446 if (klass->name_space && *klass->name_space)
447 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
449 full_name = g_strdup (klass->name);
451 MonoException *exc_to_throw = mono_get_exception_type_initialization_checked (full_name, exc, error);
453 return_val_if_nok (error, FALSE);
455 mono_error_set_exception_instance (error, exc_to_throw);
457 MonoException *exc_to_store = mono_error_convert_to_exception (error);
458 /* What we really want to do here is clone the error object and store one copy in the
459 * domain's exception hash and use the other one to error out here. */
460 mono_error_set_exception_instance (error, exc_to_store);
462 * Store the exception object so it could be thrown on subsequent
465 mono_domain_lock (domain);
466 if (!domain->type_init_exception_hash)
467 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");
468 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_store);
469 mono_domain_unlock (domain);
473 mono_domain_set (last_domain, TRUE);
475 mono_type_init_unlock (lock);
477 /* this just blocks until the initializing thread is done */
478 mono_type_init_lock (lock);
479 mono_type_init_unlock (lock);
482 mono_type_initialization_lock ();
483 if (!mono_native_thread_id_equals (lock->initializing_tid, tid))
484 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
485 --lock->waiting_count;
486 if (lock->waiting_count == 0) {
487 mono_coop_mutex_destroy (&lock->initialization_section);
488 g_hash_table_remove (type_initialization_hash, vtable);
491 mono_memory_barrier ();
492 if (!vtable->init_failed)
493 vtable->initialized = 1;
494 mono_type_initialization_unlock ();
496 if (vtable->init_failed) {
497 /* Either we were the initializing thread or we waited for the initialization */
498 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
505 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
507 MONO_REQ_GC_NEUTRAL_MODE;
509 MonoVTable *vtable = (MonoVTable*)key;
511 TypeInitializationLock *lock = (TypeInitializationLock*) value;
512 if (mono_native_thread_id_equals (lock->initializing_tid, MONO_UINT_TO_NATIVE_THREAD_ID (GPOINTER_TO_UINT (user))) && !lock->done) {
515 * Have to set this since it cannot be set by the normal code in
516 * mono_runtime_class_init (). In this case, the exception object is not stored,
517 * and get_type_init_exception_for_class () needs to be aware of this.
519 vtable->init_failed = 1;
520 mono_type_init_unlock (lock);
521 --lock->waiting_count;
522 if (lock->waiting_count == 0) {
523 mono_coop_mutex_destroy (&lock->initialization_section);
532 mono_release_type_locks (MonoInternalThread *thread)
534 MONO_REQ_GC_UNSAFE_MODE;
536 mono_type_initialization_lock ();
537 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, GUINT_TO_POINTER (thread->tid));
538 mono_type_initialization_unlock ();
541 #ifndef DISABLE_REMOTING
544 default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error)
546 g_error ("remoting not installed");
550 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
554 default_delegate_trampoline (MonoDomain *domain, MonoClass *klass)
556 g_assert_not_reached ();
560 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
561 static MonoImtThunkBuilder imt_thunk_builder;
562 static gboolean always_build_imt_thunks;
564 #if (MONO_IMT_SIZE > 32)
565 #error "MONO_IMT_SIZE cannot be larger than 32"
569 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
571 memcpy (&callbacks, cbs, sizeof (*cbs));
574 MonoRuntimeCallbacks*
575 mono_get_runtime_callbacks (void)
580 #ifndef DISABLE_REMOTING
582 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
584 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
589 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
591 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
595 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
596 imt_thunk_builder = func;
600 mono_set_always_build_imt_thunks (gboolean value)
602 always_build_imt_thunks = value;
606 * mono_compile_method:
607 * @method: The method to compile.
609 * This JIT-compiles the method, and returns the pointer to the native code
613 mono_compile_method (MonoMethod *method)
616 gpointer result = mono_compile_method_checked (method, &error);
617 mono_error_cleanup (&error);
622 * mono_compile_method:
623 * @method: The method to compile.
624 * @error: set on error.
626 * This JIT-compiles the method, and returns the pointer to the native code
627 * produced. On failure returns NULL and sets @error.
630 mono_compile_method_checked (MonoMethod *method, MonoError *error)
634 MONO_REQ_GC_NEUTRAL_MODE
636 mono_error_init (error);
638 if (!callbacks.compile_method) {
639 g_error ("compile method called on uninitialized runtime");
642 res = callbacks.compile_method (method, error);
647 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper, MonoError *error)
651 MONO_REQ_GC_NEUTRAL_MODE;
653 mono_error_init (error);
654 res = callbacks.create_jump_trampoline (domain, method, add_sync_wrapper, error);
659 mono_runtime_create_delegate_trampoline (MonoClass *klass)
661 MONO_REQ_GC_NEUTRAL_MODE
663 return arch_create_delegate_trampoline (mono_domain_get (), klass);
666 static MonoFreeMethodFunc default_mono_free_method = NULL;
669 * mono_install_free_method:
670 * @func: pointer to the MonoFreeMethodFunc used to release a method
672 * This is an internal VM routine, it is used for the engines to
673 * register a handler to release the resources associated with a method.
675 * Methods are freed when no more references to the delegate that holds
679 mono_install_free_method (MonoFreeMethodFunc func)
681 default_mono_free_method = func;
685 * mono_runtime_free_method:
686 * @domain; domain where the method is hosted
687 * @method: method to release
689 * This routine is invoked to free the resources associated with
690 * a method that has been JIT compiled. This is used to discard
691 * methods that were used only temporarily (for example, used in marshalling)
695 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
697 MONO_REQ_GC_NEUTRAL_MODE
699 if (default_mono_free_method != NULL)
700 default_mono_free_method (domain, method);
702 mono_method_clear_object (domain, method);
704 mono_free_method (method);
708 * The vtables in the root appdomain are assumed to be reachable by other
709 * roots, and we don't use typed allocation in the other domains.
712 /* The sync block is no longer a GC pointer */
713 #define GC_HEADER_BITMAP (0)
715 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
718 compute_class_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
720 MONO_REQ_GC_NEUTRAL_MODE;
722 MonoClassField *field;
728 max_size = mono_class_data_size (klass) / sizeof (gpointer);
730 max_size = klass->instance_size / sizeof (gpointer);
731 if (max_size > size) {
732 g_assert (offset <= 0);
733 bitmap = (gsize *)g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
738 /*An Ephemeron cannot be marked by sgen*/
739 if (!static_fields && klass->image == mono_defaults.corlib && !strcmp ("Ephemeron", klass->name)) {
741 memset (bitmap, 0, size / 8);
746 for (p = klass; p != NULL; p = p->parent) {
747 gpointer iter = NULL;
748 while ((field = mono_class_get_fields (p, &iter))) {
752 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
754 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
757 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
760 /* FIXME: should not happen, flag as type load error */
761 if (field->type->byref)
764 if (static_fields && field->offset == -1)
768 pos = field->offset / sizeof (gpointer);
771 type = mono_type_get_underlying_type (field->type);
772 switch (type->type) {
775 case MONO_TYPE_FNPTR:
777 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
782 if (klass->image != mono_defaults.corlib)
785 case MONO_TYPE_STRING:
786 case MONO_TYPE_SZARRAY:
787 case MONO_TYPE_CLASS:
788 case MONO_TYPE_OBJECT:
789 case MONO_TYPE_ARRAY:
790 g_assert ((field->offset % sizeof(gpointer)) == 0);
792 g_assert (pos < size || pos <= max_size);
793 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
794 *max_set = MAX (*max_set, pos);
796 case MONO_TYPE_GENERICINST:
797 if (!mono_type_generic_inst_is_valuetype (type)) {
798 g_assert ((field->offset % sizeof(gpointer)) == 0);
800 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
801 *max_set = MAX (*max_set, pos);
806 case MONO_TYPE_VALUETYPE: {
807 MonoClass *fclass = mono_class_from_mono_type (field->type);
808 if (fclass->has_references) {
809 /* remove the object header */
810 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
824 case MONO_TYPE_BOOLEAN:
828 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
839 * mono_class_compute_bitmap:
841 * Mono internal function to compute a bitmap of reference fields in a class.
844 mono_class_compute_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
846 MONO_REQ_GC_NEUTRAL_MODE;
848 return compute_class_bitmap (klass, bitmap, size, offset, max_set, static_fields);
853 * similar to the above, but sets the bits in the bitmap for any non-ref field
854 * and ignores static fields
857 compute_class_non_ref_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset)
859 MonoClassField *field;
864 max_size = class->instance_size / sizeof (gpointer);
865 if (max_size >= size) {
866 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
869 for (p = class; p != NULL; p = p->parent) {
870 gpointer iter = NULL;
871 while ((field = mono_class_get_fields (p, &iter))) {
874 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
876 /* FIXME: should not happen, flag as type load error */
877 if (field->type->byref)
880 pos = field->offset / sizeof (gpointer);
883 type = mono_type_get_underlying_type (field->type);
884 switch (type->type) {
885 #if SIZEOF_VOID_P == 8
889 case MONO_TYPE_FNPTR:
894 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
895 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
896 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
899 #if SIZEOF_VOID_P == 4
903 case MONO_TYPE_FNPTR:
908 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
909 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
910 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
916 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
917 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
918 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
921 case MONO_TYPE_BOOLEAN:
924 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
926 case MONO_TYPE_STRING:
927 case MONO_TYPE_SZARRAY:
928 case MONO_TYPE_CLASS:
929 case MONO_TYPE_OBJECT:
930 case MONO_TYPE_ARRAY:
932 case MONO_TYPE_GENERICINST:
933 if (!mono_type_generic_inst_is_valuetype (type)) {
938 case MONO_TYPE_VALUETYPE: {
939 MonoClass *fclass = mono_class_from_mono_type (field->type);
940 /* remove the object header */
941 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
945 g_assert_not_reached ();
954 * mono_class_insecure_overlapping:
955 * check if a class with explicit layout has references and non-references
956 * fields overlapping.
958 * Returns: TRUE if it is insecure to load the type.
961 mono_class_insecure_overlapping (MonoClass *klass)
965 gsize default_bitmap [4] = {0};
967 gsize default_nrbitmap [4] = {0};
968 int i, insecure = FALSE;
971 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
972 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
974 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
975 int idx = i % (sizeof (bitmap [0]) * 8);
976 if (bitmap [idx] & nrbitmap [idx]) {
981 if (bitmap != default_bitmap)
983 if (nrbitmap != default_nrbitmap)
986 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
994 ves_icall_string_alloc (int length)
997 MonoString *str = mono_string_new_size_checked (mono_domain_get (), length, &error);
998 mono_error_set_pending_exception (&error);
1004 mono_class_compute_gc_descriptor (MonoClass *klass)
1006 MONO_REQ_GC_NEUTRAL_MODE;
1010 gsize default_bitmap [4] = {0};
1011 static gboolean gcj_inited = FALSE;
1014 mono_loader_lock ();
1016 mono_register_jit_icall (ves_icall_object_new_fast, "ves_icall_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
1017 mono_register_jit_icall (ves_icall_string_alloc, "ves_icall_string_alloc", mono_create_icall_signature ("object int"), FALSE);
1020 mono_loader_unlock ();
1024 mono_class_init (klass);
1026 if (klass->gc_descr_inited)
1029 klass->gc_descr_inited = TRUE;
1030 klass->gc_descr = MONO_GC_DESCRIPTOR_NULL;
1032 bitmap = default_bitmap;
1033 if (klass == mono_defaults.string_class) {
1034 klass->gc_descr = mono_gc_make_descr_for_string (bitmap, 2);
1035 } else if (klass->rank) {
1036 mono_class_compute_gc_descriptor (klass->element_class);
1037 if (MONO_TYPE_IS_REFERENCE (&klass->element_class->byval_arg)) {
1039 klass->gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
1040 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1041 class->name_space, class->name);*/
1043 /* remove the object header */
1044 bitmap = compute_class_bitmap (klass->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
1045 klass->gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, bitmap, mono_array_element_size (klass) / sizeof (gpointer), mono_array_element_size (klass));
1046 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1047 class->name_space, class->name);*/
1048 if (bitmap != default_bitmap)
1052 /*static int count = 0;
1055 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1056 klass->gc_descr = mono_gc_make_descr_for_object (bitmap, max_set + 1, klass->instance_size);
1058 if (class->gc_descr == MONO_GC_DESCRIPTOR_NULL)
1059 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
1061 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
1062 if (bitmap != default_bitmap)
1068 * field_is_special_static:
1069 * @fklass: The MonoClass to look up.
1070 * @field: The MonoClassField describing the field.
1072 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1073 * SPECIAL_STATIC_NONE otherwise.
1076 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1078 MONO_REQ_GC_NEUTRAL_MODE;
1081 MonoCustomAttrInfo *ainfo;
1083 ainfo = mono_custom_attrs_from_field_checked (fklass, field, &error);
1084 mono_error_cleanup (&error); /* FIXME don't swallow the error? */
1087 for (i = 0; i < ainfo->num_attrs; ++i) {
1088 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1089 if (klass->image == mono_defaults.corlib) {
1090 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1091 mono_custom_attrs_free (ainfo);
1092 return SPECIAL_STATIC_THREAD;
1094 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1095 mono_custom_attrs_free (ainfo);
1096 return SPECIAL_STATIC_CONTEXT;
1100 mono_custom_attrs_free (ainfo);
1101 return SPECIAL_STATIC_NONE;
1104 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1105 #define mix(a,b,c) { \
1106 a -= c; a ^= rot(c, 4); c += b; \
1107 b -= a; b ^= rot(a, 6); a += c; \
1108 c -= b; c ^= rot(b, 8); b += a; \
1109 a -= c; a ^= rot(c,16); c += b; \
1110 b -= a; b ^= rot(a,19); a += c; \
1111 c -= b; c ^= rot(b, 4); b += a; \
1113 #define final(a,b,c) { \
1114 c ^= b; c -= rot(b,14); \
1115 a ^= c; a -= rot(c,11); \
1116 b ^= a; b -= rot(a,25); \
1117 c ^= b; c -= rot(b,16); \
1118 a ^= c; a -= rot(c,4); \
1119 b ^= a; b -= rot(a,14); \
1120 c ^= b; c -= rot(b,24); \
1124 * mono_method_get_imt_slot:
1126 * The IMT slot is embedded into AOTed code, so this must return the same value
1127 * for the same method across all executions. This means:
1128 * - pointers shouldn't be used as hash values.
1129 * - mono_metadata_str_hash () should be used for hashing strings.
1132 mono_method_get_imt_slot (MonoMethod *method)
1134 MONO_REQ_GC_NEUTRAL_MODE;
1136 MonoMethodSignature *sig;
1138 guint32 *hashes_start, *hashes;
1142 /* This can be used to stress tests the collision code */
1146 * We do this to simplify generic sharing. It will hurt
1147 * performance in cases where a class implements two different
1148 * instantiations of the same generic interface.
1149 * The code in build_imt_slots () depends on this.
1151 if (method->is_inflated)
1152 method = ((MonoMethodInflated*)method)->declaring;
1154 sig = mono_method_signature (method);
1155 hashes_count = sig->param_count + 4;
1156 hashes_start = (guint32 *)malloc (hashes_count * sizeof (guint32));
1157 hashes = hashes_start;
1159 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1160 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1161 method->klass->name_space, method->klass->name, method->name);
1164 /* Initialize hashes */
1165 hashes [0] = mono_metadata_str_hash (method->klass->name);
1166 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1167 hashes [2] = mono_metadata_str_hash (method->name);
1168 hashes [3] = mono_metadata_type_hash (sig->ret);
1169 for (i = 0; i < sig->param_count; i++) {
1170 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1173 /* Setup internal state */
1174 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1176 /* Handle most of the hashes */
1177 while (hashes_count > 3) {
1186 /* Handle the last 3 hashes (all the case statements fall through) */
1187 switch (hashes_count) {
1188 case 3 : c += hashes [2];
1189 case 2 : b += hashes [1];
1190 case 1 : a += hashes [0];
1192 case 0: /* nothing left to add */
1196 free (hashes_start);
1197 /* Report the result */
1198 return c % MONO_IMT_SIZE;
1207 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1208 MONO_REQ_GC_NEUTRAL_MODE;
1210 guint32 imt_slot = mono_method_get_imt_slot (method);
1211 MonoImtBuilderEntry *entry;
1213 if (slot_num >= 0 && imt_slot != slot_num) {
1214 /* we build just a single imt slot and this is not it */
1218 entry = (MonoImtBuilderEntry *)g_malloc0 (sizeof (MonoImtBuilderEntry));
1219 entry->key = method;
1220 entry->value.vtable_slot = vtable_slot;
1221 entry->next = imt_builder [imt_slot];
1222 if (imt_builder [imt_slot] != NULL) {
1223 entry->children = imt_builder [imt_slot]->children + 1;
1224 if (entry->children == 1) {
1225 mono_stats.imt_slots_with_collisions++;
1226 *imt_collisions_bitmap |= (1 << imt_slot);
1229 entry->children = 0;
1230 mono_stats.imt_used_slots++;
1232 imt_builder [imt_slot] = entry;
1235 char *method_name = mono_method_full_name (method, TRUE);
1236 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1237 method, method_name, imt_slot, vtable_slot, entry->children);
1238 g_free (method_name);
1245 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1247 MonoMethod *method = e->key;
1248 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1252 method->klass->name_space,
1253 method->klass->name,
1256 printf (" * %s: NULL\n", message);
1262 compare_imt_builder_entries (const void *p1, const void *p2) {
1263 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1264 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1266 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1270 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1272 MONO_REQ_GC_NEUTRAL_MODE;
1274 int count = end - start;
1275 int chunk_start = out_array->len;
1278 for (i = start; i < end; ++i) {
1279 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1280 item->key = sorted_array [i]->key;
1281 item->value = sorted_array [i]->value;
1282 item->has_target_code = sorted_array [i]->has_target_code;
1283 item->is_equals = TRUE;
1285 item->check_target_idx = out_array->len + 1;
1287 item->check_target_idx = 0;
1288 g_ptr_array_add (out_array, item);
1291 int middle = start + count / 2;
1292 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1294 item->key = sorted_array [middle]->key;
1295 item->is_equals = FALSE;
1296 g_ptr_array_add (out_array, item);
1297 imt_emit_ir (sorted_array, start, middle, out_array);
1298 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1304 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1305 MONO_REQ_GC_NEUTRAL_MODE;
1307 int number_of_entries = entries->children + 1;
1308 MonoImtBuilderEntry **sorted_array = (MonoImtBuilderEntry **)malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1309 GPtrArray *result = g_ptr_array_new ();
1310 MonoImtBuilderEntry *current_entry;
1313 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1314 sorted_array [i] = current_entry;
1316 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1318 /*for (i = 0; i < number_of_entries; i++) {
1319 print_imt_entry (" sorted array:", sorted_array [i], i);
1322 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1324 free (sorted_array);
1329 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1331 MONO_REQ_GC_NEUTRAL_MODE;
1333 if (imt_builder_entry != NULL) {
1334 if (imt_builder_entry->children == 0 && !fail_tramp && !always_build_imt_thunks) {
1335 /* No collision, return the vtable slot contents */
1336 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1338 /* Collision, build the thunk */
1339 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1342 result = imt_thunk_builder (vtable, domain,
1343 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1344 for (i = 0; i < imt_ir->len; ++i)
1345 g_free (g_ptr_array_index (imt_ir, i));
1346 g_ptr_array_free (imt_ir, TRUE);
1358 static MonoImtBuilderEntry*
1359 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1362 * LOCKING: requires the loader and domain locks.
1366 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1368 MONO_REQ_GC_NEUTRAL_MODE;
1372 guint32 imt_collisions_bitmap = 0;
1373 MonoImtBuilderEntry **imt_builder = (MonoImtBuilderEntry **)calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1374 int method_count = 0;
1375 gboolean record_method_count_for_max_collisions = FALSE;
1376 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1379 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1381 for (i = 0; i < klass->interface_offsets_count; ++i) {
1382 MonoClass *iface = klass->interfaces_packed [i];
1383 int interface_offset = klass->interface_offsets_packed [i];
1384 int method_slot_in_interface, vt_slot;
1386 if (mono_class_has_variant_generic_params (iface))
1387 has_variant_iface = TRUE;
1389 mono_class_setup_methods (iface);
1390 vt_slot = interface_offset;
1391 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1394 if (slot_num >= 0 && iface->is_inflated) {
1396 * The imt slot of the method is the same as for its declaring method,
1397 * see the comment in mono_method_get_imt_slot (), so we can
1398 * avoid inflating methods which will be discarded by
1399 * add_imt_builder_entry anyway.
1401 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1402 if (mono_method_get_imt_slot (method) != slot_num) {
1407 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1408 if (method->is_generic) {
1409 has_generic_virtual = TRUE;
1414 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1415 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1420 if (extra_interfaces) {
1421 int interface_offset = klass->vtable_size;
1423 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1424 MonoClass* iface = (MonoClass *)list_item->data;
1425 int method_slot_in_interface;
1426 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1427 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1429 if (method->is_generic)
1430 has_generic_virtual = TRUE;
1431 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1433 interface_offset += iface->method.count;
1436 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1437 /* overwrite the imt slot only if we're building all the entries or if
1438 * we're building this specific one
1440 if (slot_num < 0 || i == slot_num) {
1441 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1444 if (imt_builder [i]) {
1445 MonoImtBuilderEntry *entry;
1447 /* Link entries with imt_builder [i] */
1448 for (entry = entries; entry->next; entry = entry->next) {
1450 MonoMethod *method = (MonoMethod*)entry->key;
1451 char *method_name = mono_method_full_name (method, TRUE);
1452 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1453 g_free (method_name);
1456 entry->next = imt_builder [i];
1457 entries->children += imt_builder [i]->children + 1;
1459 imt_builder [i] = entries;
1462 if (has_generic_virtual || has_variant_iface) {
1464 * There might be collisions later when the the thunk is expanded.
1466 imt_collisions_bitmap |= (1 << i);
1469 * The IMT thunk might be called with an instance of one of the
1470 * generic virtual methods, so has to fallback to the IMT trampoline.
1472 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline (vt, i));
1474 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1477 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1481 if (imt_builder [i] != NULL) {
1482 int methods_in_slot = imt_builder [i]->children + 1;
1483 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1484 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1485 record_method_count_for_max_collisions = TRUE;
1487 method_count += methods_in_slot;
1491 mono_stats.imt_number_of_methods += method_count;
1492 if (record_method_count_for_max_collisions) {
1493 mono_stats.imt_method_count_when_max_collisions = method_count;
1496 for (i = 0; i < MONO_IMT_SIZE; i++) {
1497 MonoImtBuilderEntry* entry = imt_builder [i];
1498 while (entry != NULL) {
1499 MonoImtBuilderEntry* next = entry->next;
1505 /* we OR the bitmap since we may build just a single imt slot at a time */
1506 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1510 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1511 MONO_REQ_GC_NEUTRAL_MODE;
1513 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1517 * mono_vtable_build_imt_slot:
1518 * @vtable: virtual object table struct
1519 * @imt_slot: slot in the IMT table
1521 * Fill the given @imt_slot in the IMT table of @vtable with
1522 * a trampoline or a thunk for the case of collisions.
1523 * This is part of the internal mono API.
1525 * LOCKING: Take the domain lock.
1528 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1530 MONO_REQ_GC_NEUTRAL_MODE;
1532 gpointer *imt = (gpointer*)vtable;
1533 imt -= MONO_IMT_SIZE;
1534 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1536 /* no support for extra interfaces: the proxy objects will need
1537 * to build the complete IMT
1538 * Update and heck needs to ahppen inside the proper domain lock, as all
1539 * the changes made to a MonoVTable.
1541 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1542 mono_domain_lock (vtable->domain);
1543 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1544 if (!callbacks.imt_entry_inited (vtable, imt_slot))
1545 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1546 mono_domain_unlock (vtable->domain);
1547 mono_loader_unlock ();
1552 * The first two free list entries both belong to the wait list: The
1553 * first entry is the pointer to the head of the list and the second
1554 * entry points to the last element. That way appending and removing
1555 * the first element are both O(1) operations.
1557 #ifdef MONO_SMALL_CONFIG
1558 #define NUM_FREE_LISTS 6
1560 #define NUM_FREE_LISTS 12
1562 #define FIRST_FREE_LIST_SIZE 64
1563 #define MAX_WAIT_LENGTH 50
1564 #define THUNK_THRESHOLD 10
1567 * LOCKING: The domain lock must be held.
1570 init_thunk_free_lists (MonoDomain *domain)
1572 MONO_REQ_GC_NEUTRAL_MODE;
1574 if (domain->thunk_free_lists)
1576 domain->thunk_free_lists = (MonoThunkFreeList **)mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1580 list_index_for_size (int item_size)
1583 int size = FIRST_FREE_LIST_SIZE;
1585 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1594 * mono_method_alloc_generic_virtual_thunk:
1596 * @size: size in bytes
1598 * Allocs size bytes to be used for the code of a generic virtual
1599 * thunk. It's either allocated from the domain's code manager or
1600 * reused from a previously invalidated piece.
1602 * LOCKING: The domain lock must be held.
1605 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1607 MONO_REQ_GC_NEUTRAL_MODE;
1609 static gboolean inited = FALSE;
1610 static int generic_virtual_thunks_size = 0;
1614 MonoThunkFreeList **l;
1616 init_thunk_free_lists (domain);
1618 size += sizeof (guint32);
1619 if (size < sizeof (MonoThunkFreeList))
1620 size = sizeof (MonoThunkFreeList);
1622 i = list_index_for_size (size);
1623 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1624 if ((*l)->size >= size) {
1625 MonoThunkFreeList *item = *l;
1627 return ((guint32*)item) + 1;
1631 /* no suitable item found - search lists of larger sizes */
1632 while (++i < NUM_FREE_LISTS) {
1633 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1636 g_assert (item->size > size);
1637 domain->thunk_free_lists [i] = item->next;
1638 return ((guint32*)item) + 1;
1641 /* still nothing found - allocate it */
1643 mono_counters_register ("Generic virtual thunk bytes",
1644 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1647 generic_virtual_thunks_size += size;
1649 p = (guint32 *)mono_domain_code_reserve (domain, size);
1652 mono_domain_lock (domain);
1653 if (!domain->generic_virtual_thunks)
1654 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1655 g_hash_table_insert (domain->generic_virtual_thunks, p, p);
1656 mono_domain_unlock (domain);
1662 * LOCKING: The domain lock must be held.
1665 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1667 MONO_REQ_GC_NEUTRAL_MODE;
1669 guint32 *p = (guint32 *)code;
1670 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1671 gboolean found = FALSE;
1673 mono_domain_lock (domain);
1674 if (!domain->generic_virtual_thunks)
1675 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1676 if (g_hash_table_lookup (domain->generic_virtual_thunks, l))
1678 mono_domain_unlock (domain);
1681 /* Not allocated by mono_method_alloc_generic_virtual_thunk (), i.e. AOT */
1683 init_thunk_free_lists (domain);
1685 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1686 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1687 int length = item->length;
1690 /* unlink the first item from the wait list */
1691 domain->thunk_free_lists [0] = item->next;
1692 domain->thunk_free_lists [0]->length = length - 1;
1694 i = list_index_for_size (item->size);
1696 /* put it in the free list */
1697 item->next = domain->thunk_free_lists [i];
1698 domain->thunk_free_lists [i] = item;
1702 if (domain->thunk_free_lists [1]) {
1703 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1704 domain->thunk_free_lists [0]->length++;
1706 g_assert (!domain->thunk_free_lists [0]);
1708 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1709 domain->thunk_free_lists [0]->length = 1;
1713 typedef struct _GenericVirtualCase {
1717 struct _GenericVirtualCase *next;
1718 } GenericVirtualCase;
1721 * get_generic_virtual_entries:
1723 * Return IMT entries for the generic virtual method instances and
1724 * variant interface methods for vtable slot
1727 static MonoImtBuilderEntry*
1728 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1730 MONO_REQ_GC_NEUTRAL_MODE;
1732 GenericVirtualCase *list;
1733 MonoImtBuilderEntry *entries;
1735 mono_domain_lock (domain);
1736 if (!domain->generic_virtual_cases)
1737 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1739 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1742 for (; list; list = list->next) {
1743 MonoImtBuilderEntry *entry;
1745 if (list->count < THUNK_THRESHOLD)
1748 entry = g_new0 (MonoImtBuilderEntry, 1);
1749 entry->key = list->method;
1750 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1751 entry->has_target_code = 1;
1753 entry->children = entries->children + 1;
1754 entry->next = entries;
1758 mono_domain_unlock (domain);
1760 /* FIXME: Leaking memory ? */
1765 * mono_method_add_generic_virtual_invocation:
1767 * @vtable_slot: pointer to the vtable slot
1768 * @method: the inflated generic virtual method
1769 * @code: the method's code
1771 * Registers a call via unmanaged code to a generic virtual method
1772 * instantiation or variant interface method. If the number of calls reaches a threshold
1773 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1774 * virtual method thunk.
1777 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1778 gpointer *vtable_slot,
1779 MonoMethod *method, gpointer code)
1781 MONO_REQ_GC_NEUTRAL_MODE;
1783 static gboolean inited = FALSE;
1784 static int num_added = 0;
1786 GenericVirtualCase *gvc, *list;
1787 MonoImtBuilderEntry *entries;
1791 mono_domain_lock (domain);
1792 if (!domain->generic_virtual_cases)
1793 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1795 /* Check whether the case was already added */
1796 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1799 if (gvc->method == method)
1804 /* If not found, make a new one */
1806 gvc = (GenericVirtualCase *)mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1807 gvc->method = method;
1810 gvc->next = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1812 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1815 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1821 if (++gvc->count == THUNK_THRESHOLD) {
1822 gpointer *old_thunk = (void **)*vtable_slot;
1823 gpointer vtable_trampoline = NULL;
1824 gpointer imt_trampoline = NULL;
1826 if ((gpointer)vtable_slot < (gpointer)vtable) {
1827 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1828 int imt_slot = MONO_IMT_SIZE + displacement;
1830 /* Force the rebuild of the thunk at the next call */
1831 imt_trampoline = callbacks.get_imt_trampoline (vtable, imt_slot);
1832 *vtable_slot = imt_trampoline;
1834 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline (vtable, (gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1836 entries = get_generic_virtual_entries (domain, vtable_slot);
1838 sorted = imt_sort_slot_entries (entries);
1840 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1844 MonoImtBuilderEntry *next = entries->next;
1849 for (i = 0; i < sorted->len; ++i)
1850 g_free (g_ptr_array_index (sorted, i));
1851 g_ptr_array_free (sorted, TRUE);
1854 #ifndef __native_client__
1855 /* We don't re-use any thunks as there is a lot of overhead */
1856 /* to deleting and re-using code in Native Client. */
1857 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1858 invalidate_generic_virtual_thunk (domain, old_thunk);
1862 mono_domain_unlock (domain);
1865 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error);
1868 * mono_class_vtable:
1869 * @domain: the application domain
1870 * @class: the class to initialize
1872 * VTables are domain specific because we create domain specific code, and
1873 * they contain the domain specific static class data.
1874 * On failure, NULL is returned, and class->exception_type is set.
1877 mono_class_vtable (MonoDomain *domain, MonoClass *klass)
1880 MonoVTable* vtable = mono_class_vtable_full (domain, klass, &error);
1881 mono_error_cleanup (&error);
1886 * mono_class_vtable_full:
1887 * @domain: the application domain
1888 * @class: the class to initialize
1889 * @error set on failure.
1891 * VTables are domain specific because we create domain specific code, and
1892 * they contain the domain specific static class data.
1895 mono_class_vtable_full (MonoDomain *domain, MonoClass *klass, MonoError *error)
1897 MONO_REQ_GC_UNSAFE_MODE;
1899 MonoClassRuntimeInfo *runtime_info;
1901 mono_error_init (error);
1905 if (mono_class_has_failure (klass)) {
1906 mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (klass));
1910 /* this check can be inlined in jitted code, too */
1911 runtime_info = klass->runtime_info;
1912 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1913 return runtime_info->domain_vtables [domain->domain_id];
1914 return mono_class_create_runtime_vtable (domain, klass, error);
1918 * mono_class_try_get_vtable:
1919 * @domain: the application domain
1920 * @class: the class to initialize
1922 * This function tries to get the associated vtable from @class if
1923 * it was already created.
1926 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *klass)
1928 MONO_REQ_GC_NEUTRAL_MODE;
1930 MonoClassRuntimeInfo *runtime_info;
1934 runtime_info = klass->runtime_info;
1935 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1936 return runtime_info->domain_vtables [domain->domain_id];
1941 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1943 MONO_REQ_GC_NEUTRAL_MODE;
1945 size_t alloc_offset;
1948 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1949 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1950 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1952 if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1953 g_assert ((imt_table_bytes & 7) == 4);
1960 return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1964 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error)
1966 MONO_REQ_GC_UNSAFE_MODE;
1969 MonoClassRuntimeInfo *runtime_info, *old_info;
1970 MonoClassField *field;
1972 int i, vtable_slots;
1973 size_t imt_table_bytes;
1975 guint32 vtable_size, class_size;
1977 gpointer *interface_offsets;
1979 mono_error_init (error);
1981 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1982 mono_domain_lock (domain);
1983 runtime_info = klass->runtime_info;
1984 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1985 mono_domain_unlock (domain);
1986 mono_loader_unlock ();
1987 return runtime_info->domain_vtables [domain->domain_id];
1989 if (!klass->inited || mono_class_has_failure (klass)) {
1990 if (!mono_class_init (klass) || mono_class_has_failure (klass)) {
1991 mono_domain_unlock (domain);
1992 mono_loader_unlock ();
1993 mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (klass));
1998 /* Array types require that their element type be valid*/
1999 if (klass->byval_arg.type == MONO_TYPE_ARRAY || klass->byval_arg.type == MONO_TYPE_SZARRAY) {
2000 MonoClass *element_class = klass->element_class;
2001 if (!element_class->inited)
2002 mono_class_init (element_class);
2004 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
2005 if (!mono_class_has_failure (element_class) && !element_class->vtable_size)
2006 mono_class_setup_vtable (element_class);
2008 if (mono_class_has_failure (element_class)) {
2009 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
2010 if (!mono_class_has_failure (klass))
2011 mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
2012 mono_domain_unlock (domain);
2013 mono_loader_unlock ();
2014 mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (klass));
2020 * For some classes, mono_class_init () already computed klass->vtable_size, and
2021 * that is all that is needed because of the vtable trampolines.
2023 if (!klass->vtable_size)
2024 mono_class_setup_vtable (klass);
2026 if (klass->generic_class && !klass->vtable)
2027 mono_class_check_vtable_constraints (klass, NULL);
2029 /* Initialize klass->has_finalize */
2030 mono_class_has_finalizer (klass);
2032 if (mono_class_has_failure (klass)) {
2033 mono_domain_unlock (domain);
2034 mono_loader_unlock ();
2035 mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (klass));
2039 vtable_slots = klass->vtable_size;
2040 /* we add an additional vtable slot to store the pointer to static field data only when needed */
2041 class_size = mono_class_data_size (klass);
2045 if (klass->interface_offsets_count) {
2046 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
2047 mono_stats.imt_number_of_tables++;
2048 mono_stats.imt_tables_size += imt_table_bytes;
2050 imt_table_bytes = 0;
2053 vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
2055 mono_stats.used_class_count++;
2056 mono_stats.class_vtable_size += vtable_size;
2058 interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
2059 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2060 g_assert (!((gsize)vt & 7));
2063 vt->rank = klass->rank;
2064 vt->domain = domain;
2066 mono_class_compute_gc_descriptor (klass);
2068 * We can't use typed allocation in the non-root domains, since the
2069 * collector needs the GC descriptor stored in the vtable even after
2070 * the mempool containing the vtable is destroyed when the domain is
2071 * unloaded. An alternative might be to allocate vtables in the GC
2072 * heap, but this does not seem to work (it leads to crashes inside
2073 * libgc). If that approach is tried, two gc descriptors need to be
2074 * allocated for each class: one for the root domain, and one for all
2075 * other domains. The second descriptor should contain a bit for the
2076 * vtable field in MonoObject, since we can no longer assume the
2077 * vtable is reachable by other roots after the appdomain is unloaded.
2079 #ifdef HAVE_BOEHM_GC
2080 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
2081 vt->gc_descr = MONO_GC_DESCRIPTOR_NULL;
2084 vt->gc_descr = klass->gc_descr;
2086 gc_bits = mono_gc_get_vtable_bits (klass);
2087 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
2089 vt->gc_bits = gc_bits;
2092 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
2093 if (klass->has_static_refs) {
2094 MonoGCDescriptor statics_gc_descr;
2096 gsize default_bitmap [4] = {0};
2099 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
2100 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], klass->name_space, klass->name, class_size);*/
2101 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
2102 vt->vtable [klass->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr, MONO_ROOT_SOURCE_STATIC, "managed static variables");
2103 mono_domain_add_class_static_data (domain, klass, vt->vtable [klass->vtable_size], NULL);
2104 if (bitmap != default_bitmap)
2107 vt->vtable [klass->vtable_size] = mono_domain_alloc0 (domain, class_size);
2109 vt->has_static_fields = TRUE;
2110 mono_stats.class_static_data_size += class_size;
2114 while ((field = mono_class_get_fields (klass, &iter))) {
2115 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2117 if (mono_field_is_deleted (field))
2119 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2120 gint32 special_static = klass->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (klass, field);
2121 if (special_static != SPECIAL_STATIC_NONE) {
2122 guint32 size, offset;
2124 gsize default_bitmap [4] = {0};
2129 if (mono_type_is_reference (field->type)) {
2130 default_bitmap [0] = 1;
2132 bitmap = default_bitmap;
2133 } else if (mono_type_is_struct (field->type)) {
2134 fclass = mono_class_from_mono_type (field->type);
2135 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
2136 numbits = max_set + 1;
2138 default_bitmap [0] = 0;
2140 bitmap = default_bitmap;
2142 size = mono_type_size (field->type, &align);
2143 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
2144 if (!domain->special_static_fields)
2145 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2146 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2147 if (bitmap != default_bitmap)
2150 * This marks the field as special static to speed up the
2151 * checks in mono_field_static_get/set_value ().
2157 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2158 MonoClass *fklass = mono_class_from_mono_type (field->type);
2159 const char *data = mono_field_get_data (field);
2161 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2162 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2163 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2166 if (fklass->valuetype) {
2167 memcpy (t, data, mono_class_value_size (fklass, NULL));
2169 /* it's a pointer type: add check */
2170 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2177 vt->max_interface_id = klass->max_interface_id;
2178 vt->interface_bitmap = klass->interface_bitmap;
2180 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2181 // class->name, klass->interface_offsets_count);
2183 /* Initialize vtable */
2184 if (callbacks.get_vtable_trampoline) {
2185 // This also covers the AOT case
2186 for (i = 0; i < klass->vtable_size; ++i) {
2187 vt->vtable [i] = callbacks.get_vtable_trampoline (vt, i);
2190 mono_class_setup_vtable (klass);
2192 for (i = 0; i < klass->vtable_size; ++i) {
2195 cm = klass->vtable [i];
2197 vt->vtable [i] = callbacks.create_jit_trampoline (domain, cm, error);
2198 if (!is_ok (error)) {
2199 mono_domain_unlock (domain);
2200 mono_loader_unlock ();
2207 if (imt_table_bytes) {
2208 /* Now that the vtable is full, we can actually fill up the IMT */
2209 for (i = 0; i < MONO_IMT_SIZE; ++i)
2210 interface_offsets [i] = callbacks.get_imt_trampoline (vt, i);
2214 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2215 * re-acquire them and check if another thread has created the vtable in the meantime.
2217 /* Special case System.MonoType to avoid infinite recursion */
2218 if (klass != mono_defaults.monotype_class) {
2219 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2220 if (!is_ok (error)) {
2221 mono_domain_unlock (domain);
2222 mono_loader_unlock ();
2226 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.monotype_class)
2227 /* This is unregistered in
2228 unregister_vtable_reflection_type() in
2230 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2233 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (klass));
2235 /* class_vtable_array keeps an array of created vtables
2237 g_ptr_array_add (domain->class_vtable_array, vt);
2238 /* klass->runtime_info is protected by the loader lock, both when
2239 * it it enlarged and when it is stored info.
2243 * Store the vtable in klass->runtime_info.
2244 * klass->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2246 mono_memory_barrier ();
2248 old_info = klass->runtime_info;
2249 if (old_info && old_info->max_domain >= domain->domain_id) {
2250 /* someone already created a large enough runtime info */
2251 old_info->domain_vtables [domain->domain_id] = vt;
2253 int new_size = domain->domain_id;
2255 new_size = MAX (new_size, old_info->max_domain);
2257 /* make the new size a power of two */
2259 while (new_size > i)
2262 /* this is a bounded memory retention issue: may want to
2263 * handle it differently when we'll have a rcu-like system.
2265 runtime_info = (MonoClassRuntimeInfo *)mono_image_alloc0 (klass->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2266 runtime_info->max_domain = new_size - 1;
2267 /* copy the stuff from the older info */
2269 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2271 runtime_info->domain_vtables [domain->domain_id] = vt;
2273 mono_memory_barrier ();
2274 klass->runtime_info = runtime_info;
2277 if (klass == mono_defaults.monotype_class) {
2278 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2279 if (!is_ok (error)) {
2280 mono_domain_unlock (domain);
2281 mono_loader_unlock ();
2285 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.monotype_class)
2286 /* This is unregistered in
2287 unregister_vtable_reflection_type() in
2289 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2292 mono_domain_unlock (domain);
2293 mono_loader_unlock ();
2295 /* make sure the parent is initialized */
2296 /*FIXME shouldn't this fail the current type?*/
2298 mono_class_vtable_full (domain, klass->parent, error);
2303 #ifndef DISABLE_REMOTING
2305 * mono_class_proxy_vtable:
2306 * @domain: the application domain
2307 * @remove_class: the remote class
2308 * @error: set on error
2310 * Creates a vtable for transparent proxies. It is basically
2311 * a copy of the real vtable of the class wrapped in @remote_class,
2312 * but all function pointers invoke the remoting functions, and
2313 * vtable->klass points to the transparent proxy class, and not to @class.
2315 * On failure returns NULL and sets @error
2318 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type, MonoError *error)
2320 MONO_REQ_GC_UNSAFE_MODE;
2322 MonoVTable *vt, *pvt;
2323 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2325 GSList *extra_interfaces = NULL;
2326 MonoClass *klass = remote_class->proxy_class;
2327 gpointer *interface_offsets;
2328 uint8_t *bitmap = NULL;
2330 size_t imt_table_bytes;
2332 #ifdef COMPRESSED_INTERFACE_BITMAP
2336 mono_error_init (error);
2338 vt = mono_class_vtable (domain, klass);
2339 g_assert (vt); /*FIXME property handle failure*/
2340 max_interface_id = vt->max_interface_id;
2342 /* Calculate vtable space for extra interfaces */
2343 for (j = 0; j < remote_class->interface_count; j++) {
2344 MonoClass* iclass = remote_class->interfaces[j];
2348 /*FIXME test for interfaces with variant generic arguments*/
2349 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, iclass->interface_id))
2350 continue; /* interface implemented by the class */
2351 if (g_slist_find (extra_interfaces, iclass))
2354 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2356 method_count = mono_class_num_methods (iclass);
2358 ifaces = mono_class_get_implemented_interfaces (iclass, error);
2362 for (i = 0; i < ifaces->len; ++i) {
2363 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2364 /*FIXME test for interfaces with variant generic arguments*/
2365 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, ic->interface_id))
2366 continue; /* interface implemented by the class */
2367 if (g_slist_find (extra_interfaces, ic))
2369 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2370 method_count += mono_class_num_methods (ic);
2372 g_ptr_array_free (ifaces, TRUE);
2376 extra_interface_vtsize += method_count * sizeof (gpointer);
2377 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2380 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2381 mono_stats.imt_number_of_tables++;
2382 mono_stats.imt_tables_size += imt_table_bytes;
2384 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer);
2386 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2388 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2389 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2390 g_assert (!((gsize)pvt & 7));
2392 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer));
2394 pvt->klass = mono_defaults.transparent_proxy_class;
2395 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2396 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2398 /* initialize vtable */
2399 mono_class_setup_vtable (klass);
2400 for (i = 0; i < klass->vtable_size; ++i) {
2403 if ((cm = klass->vtable [i])) {
2404 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type, error);
2408 pvt->vtable [i] = NULL;
2411 if (klass->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2412 /* create trampolines for abstract methods */
2413 for (k = klass; k; k = k->parent) {
2415 gpointer iter = NULL;
2416 while ((m = mono_class_get_methods (k, &iter)))
2417 if (!pvt->vtable [m->slot]) {
2418 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type, error);
2425 pvt->max_interface_id = max_interface_id;
2426 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2427 #ifdef COMPRESSED_INTERFACE_BITMAP
2428 bitmap = (uint8_t *)g_malloc0 (bsize);
2430 bitmap = (uint8_t *)mono_domain_alloc0 (domain, bsize);
2433 for (i = 0; i < klass->interface_offsets_count; ++i) {
2434 int interface_id = klass->interfaces_packed [i]->interface_id;
2435 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2438 if (extra_interfaces) {
2439 int slot = klass->vtable_size;
2445 /* Create trampolines for the methods of the interfaces */
2446 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2447 interf = (MonoClass *)list_item->data;
2449 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2453 while ((cm = mono_class_get_methods (interf, &iter))) {
2454 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type, error);
2459 slot += mono_class_num_methods (interf);
2463 /* Now that the vtable is full, we can actually fill up the IMT */
2464 build_imt (klass, pvt, domain, interface_offsets, extra_interfaces);
2465 if (extra_interfaces) {
2466 g_slist_free (extra_interfaces);
2469 #ifdef COMPRESSED_INTERFACE_BITMAP
2470 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2471 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2472 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2475 pvt->interface_bitmap = bitmap;
2479 if (extra_interfaces)
2480 g_slist_free (extra_interfaces);
2481 #ifdef COMPRESSED_INTERFACE_BITMAP
2487 #endif /* DISABLE_REMOTING */
2490 * mono_class_field_is_special_static:
2492 * Returns whether @field is a thread/context static field.
2495 mono_class_field_is_special_static (MonoClassField *field)
2497 MONO_REQ_GC_NEUTRAL_MODE
2499 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2501 if (mono_field_is_deleted (field))
2503 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2504 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2511 * mono_class_field_get_special_static_type:
2512 * @field: The MonoClassField describing the field.
2514 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2515 * SPECIAL_STATIC_NONE otherwise.
2518 mono_class_field_get_special_static_type (MonoClassField *field)
2520 MONO_REQ_GC_NEUTRAL_MODE
2522 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2523 return SPECIAL_STATIC_NONE;
2524 if (mono_field_is_deleted (field))
2525 return SPECIAL_STATIC_NONE;
2526 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2527 return field_is_special_static (field->parent, field);
2528 return SPECIAL_STATIC_NONE;
2532 * mono_class_has_special_static_fields:
2534 * Returns whenever @klass has any thread/context static fields.
2537 mono_class_has_special_static_fields (MonoClass *klass)
2539 MONO_REQ_GC_NEUTRAL_MODE
2541 MonoClassField *field;
2545 while ((field = mono_class_get_fields (klass, &iter))) {
2546 g_assert (field->parent == klass);
2547 if (mono_class_field_is_special_static (field))
2554 #ifndef DISABLE_REMOTING
2556 * create_remote_class_key:
2557 * Creates an array of pointers that can be used as a hash key for a remote class.
2558 * The first element of the array is the number of pointers.
2561 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2563 MONO_REQ_GC_NEUTRAL_MODE;
2568 if (remote_class == NULL) {
2569 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2570 key = (void **)g_malloc (sizeof(gpointer) * 3);
2571 key [0] = GINT_TO_POINTER (2);
2572 key [1] = mono_defaults.marshalbyrefobject_class;
2573 key [2] = extra_class;
2575 key = (void **)g_malloc (sizeof(gpointer) * 2);
2576 key [0] = GINT_TO_POINTER (1);
2577 key [1] = extra_class;
2580 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2581 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2582 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2583 key [1] = remote_class->proxy_class;
2585 // Keep the list of interfaces sorted
2586 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2587 if (extra_class && remote_class->interfaces [i] > extra_class) {
2588 key [j++] = extra_class;
2591 key [j] = remote_class->interfaces [i];
2594 key [j] = extra_class;
2596 // Replace the old class. The interface list is the same
2597 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2598 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2599 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2600 for (i = 0; i < remote_class->interface_count; i++)
2601 key [2 + i] = remote_class->interfaces [i];
2609 * copy_remote_class_key:
2611 * Make a copy of KEY in the domain and return the copy.
2614 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2616 MONO_REQ_GC_NEUTRAL_MODE
2618 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2619 gpointer *mp_key = (gpointer *)mono_domain_alloc (domain, key_size);
2621 memcpy (mp_key, key, key_size);
2627 * mono_remote_class:
2628 * @domain: the application domain
2629 * @class_name: name of the remote class
2630 * @error: set on error
2632 * Creates and initializes a MonoRemoteClass object for a remote type.
2634 * On failure returns NULL and sets @error
2637 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class, MonoError *error)
2639 MONO_REQ_GC_UNSAFE_MODE;
2641 MonoRemoteClass *rc;
2642 gpointer* key, *mp_key;
2645 mono_error_init (error);
2647 key = create_remote_class_key (NULL, proxy_class);
2649 mono_domain_lock (domain);
2650 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2654 mono_domain_unlock (domain);
2658 name = mono_string_to_utf8_mp (domain->mp, class_name, error);
2659 if (!is_ok (error)) {
2661 mono_domain_unlock (domain);
2665 mp_key = copy_remote_class_key (domain, key);
2669 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2670 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2671 rc->interface_count = 1;
2672 rc->interfaces [0] = proxy_class;
2673 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2675 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2676 rc->interface_count = 0;
2677 rc->proxy_class = proxy_class;
2680 rc->default_vtable = NULL;
2681 rc->xdomain_vtable = NULL;
2682 rc->proxy_class_name = name;
2683 #ifndef DISABLE_PERFCOUNTERS
2684 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2687 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2689 mono_domain_unlock (domain);
2694 * clone_remote_class:
2695 * Creates a copy of the remote_class, adding the provided class or interface
2697 static MonoRemoteClass*
2698 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2700 MONO_REQ_GC_NEUTRAL_MODE;
2702 MonoRemoteClass *rc;
2703 gpointer* key, *mp_key;
2705 key = create_remote_class_key (remote_class, extra_class);
2706 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2712 mp_key = copy_remote_class_key (domain, key);
2716 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2718 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2719 rc->proxy_class = remote_class->proxy_class;
2720 rc->interface_count = remote_class->interface_count + 1;
2722 // Keep the list of interfaces sorted, since the hash key of
2723 // the remote class depends on this
2724 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2725 if (remote_class->interfaces [i] > extra_class && i == j)
2726 rc->interfaces [j++] = extra_class;
2727 rc->interfaces [j] = remote_class->interfaces [i];
2730 rc->interfaces [j] = extra_class;
2732 // Replace the old class. The interface array is the same
2733 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2734 rc->proxy_class = extra_class;
2735 rc->interface_count = remote_class->interface_count;
2736 if (rc->interface_count > 0)
2737 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2740 rc->default_vtable = NULL;
2741 rc->xdomain_vtable = NULL;
2742 rc->proxy_class_name = remote_class->proxy_class_name;
2744 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2750 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp, MonoError *error)
2752 MONO_REQ_GC_UNSAFE_MODE;
2754 mono_error_init (error);
2756 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2757 mono_domain_lock (domain);
2758 if (rp->target_domain_id != -1) {
2759 if (remote_class->xdomain_vtable == NULL)
2760 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN, error);
2761 mono_domain_unlock (domain);
2762 mono_loader_unlock ();
2763 return_val_if_nok (error, NULL);
2764 return remote_class->xdomain_vtable;
2766 if (remote_class->default_vtable == NULL) {
2769 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2770 klass = mono_class_from_mono_type (type);
2772 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)))
2773 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP, error);
2776 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN, error);
2777 /* N.B. both branches of the if modify error */
2778 if (!is_ok (error)) {
2779 mono_domain_unlock (domain);
2780 mono_loader_unlock ();
2785 mono_domain_unlock (domain);
2786 mono_loader_unlock ();
2787 return remote_class->default_vtable;
2791 * mono_upgrade_remote_class:
2792 * @domain: the application domain
2793 * @tproxy: the proxy whose remote class has to be upgraded.
2794 * @klass: class to which the remote class can be casted.
2795 * @error: set on error
2797 * Updates the vtable of the remote class by adding the necessary method slots
2798 * and interface offsets so it can be safely casted to klass. klass can be a
2799 * class or an interface. On success returns TRUE, on failure returns FALSE and sets @error.
2802 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass, MonoError *error)
2804 MONO_REQ_GC_UNSAFE_MODE;
2806 MonoTransparentProxy *tproxy;
2807 MonoRemoteClass *remote_class;
2808 gboolean redo_vtable;
2810 mono_error_init (error);
2811 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2812 mono_domain_lock (domain);
2814 tproxy = (MonoTransparentProxy*) proxy_object;
2815 remote_class = tproxy->remote_class;
2817 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2820 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2821 if (remote_class->interfaces [i] == klass)
2822 redo_vtable = FALSE;
2825 redo_vtable = (remote_class->proxy_class != klass);
2829 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2830 proxy_object->vtable = (MonoVTable *)mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp, error);
2836 mono_domain_unlock (domain);
2837 mono_loader_unlock ();
2838 return is_ok (error);
2840 #endif /* DISABLE_REMOTING */
2844 * mono_object_get_virtual_method:
2845 * @obj: object to operate on.
2848 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2849 * the instance of a callvirt of method.
2852 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2854 MONO_REQ_GC_UNSAFE_MODE;
2857 MonoMethod **vtable;
2858 gboolean is_proxy = FALSE;
2859 MonoMethod *res = NULL;
2861 klass = mono_object_class (obj);
2862 #ifndef DISABLE_REMOTING
2863 if (klass == mono_defaults.transparent_proxy_class) {
2864 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2869 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2872 mono_class_setup_vtable (klass);
2873 vtable = klass->vtable;
2875 if (method->slot == -1) {
2876 /* method->slot might not be set for instances of generic methods */
2877 if (method->is_inflated) {
2878 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2879 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2882 g_assert_not_reached ();
2886 /* check method->slot is a valid index: perform isinstance? */
2887 if (method->slot != -1) {
2888 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2890 gboolean variance_used = FALSE;
2891 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2892 g_assert (iface_offset > 0);
2893 res = vtable [iface_offset + method->slot];
2896 res = vtable [method->slot];
2900 #ifndef DISABLE_REMOTING
2902 /* It may be an interface, abstract class method or generic method */
2903 if (!res || mono_method_signature (res)->generic_param_count)
2906 /* generic methods demand invoke_with_check */
2907 if (mono_method_signature (res)->generic_param_count)
2908 res = mono_marshal_get_remoting_invoke_with_check (res);
2911 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2912 res = mono_cominterop_get_invoke (res);
2915 res = mono_marshal_get_remoting_invoke (res);
2920 if (method->is_inflated) {
2922 /* Have to inflate the result */
2923 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, &error);
2924 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
2934 do_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2936 MONO_REQ_GC_UNSAFE_MODE;
2938 MonoObject *result = NULL;
2940 g_assert (callbacks.runtime_invoke);
2942 mono_error_init (error);
2944 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2945 mono_profiler_method_start_invoke (method);
2947 MONO_ENTER_GC_UNSAFE;
2949 result = callbacks.runtime_invoke (method, obj, params, exc, error);
2951 MONO_EXIT_GC_UNSAFE;
2953 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2954 mono_profiler_method_end_invoke (method);
2956 if (!mono_error_ok (error))
2963 * mono_runtime_invoke:
2964 * @method: method to invoke
2965 * @obJ: object instance
2966 * @params: arguments to the method
2967 * @exc: exception information.
2969 * Invokes the method represented by @method on the object @obj.
2971 * obj is the 'this' pointer, it should be NULL for static
2972 * methods, a MonoObject* for object instances and a pointer to
2973 * the value type for value types.
2975 * The params array contains the arguments to the method with the
2976 * same convention: MonoObject* pointers for object instances and
2977 * pointers to the value type otherwise.
2979 * From unmanaged code you'll usually use the
2980 * mono_runtime_invoke() variant.
2982 * Note that this function doesn't handle virtual methods for
2983 * you, it will exec the exact method you pass: we still need to
2984 * expose a function to lookup the derived class implementation
2985 * of a virtual method (there are examples of this in the code,
2988 * You can pass NULL as the exc argument if you don't want to
2989 * catch exceptions, otherwise, *exc will be set to the exception
2990 * thrown, if any. if an exception is thrown, you can't use the
2991 * MonoObject* result from the function.
2993 * If the method returns a value type, it is boxed in an object
2997 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
3002 res = mono_runtime_try_invoke (method, obj, params, exc, &error);
3003 if (*exc == NULL && !mono_error_ok(&error)) {
3004 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3006 mono_error_cleanup (&error);
3008 res = mono_runtime_invoke_checked (method, obj, params, &error);
3009 mono_error_raise_exception (&error);
3015 * mono_runtime_try_invoke:
3016 * @method: method to invoke
3017 * @obJ: object instance
3018 * @params: arguments to the method
3019 * @exc: exception information.
3020 * @error: set on error
3022 * Invokes the method represented by @method on the object @obj.
3024 * obj is the 'this' pointer, it should be NULL for static
3025 * methods, a MonoObject* for object instances and a pointer to
3026 * the value type for value types.
3028 * The params array contains the arguments to the method with the
3029 * same convention: MonoObject* pointers for object instances and
3030 * pointers to the value type otherwise.
3032 * From unmanaged code you'll usually use the
3033 * mono_runtime_invoke() variant.
3035 * Note that this function doesn't handle virtual methods for
3036 * you, it will exec the exact method you pass: we still need to
3037 * expose a function to lookup the derived class implementation
3038 * of a virtual method (there are examples of this in the code,
3041 * For this function, you must not pass NULL as the exc argument if
3042 * you don't want to catch exceptions, use
3043 * mono_runtime_invoke_checked(). If an exception is thrown, you
3044 * can't use the MonoObject* result from the function.
3046 * If this method cannot be invoked, @error will be set and @exc and
3047 * the return value must not be used.
3049 * If the method returns a value type, it is boxed in an object
3053 mono_runtime_try_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError* error)
3055 MONO_REQ_GC_UNSAFE_MODE;
3057 g_assert (exc != NULL);
3059 if (mono_runtime_get_no_exec ())
3060 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
3062 return do_runtime_invoke (method, obj, params, exc, error);
3066 * mono_runtime_invoke_checked:
3067 * @method: method to invoke
3068 * @obJ: object instance
3069 * @params: arguments to the method
3070 * @error: set on error
3072 * Invokes the method represented by @method on the object @obj.
3074 * obj is the 'this' pointer, it should be NULL for static
3075 * methods, a MonoObject* for object instances and a pointer to
3076 * the value type for value types.
3078 * The params array contains the arguments to the method with the
3079 * same convention: MonoObject* pointers for object instances and
3080 * pointers to the value type otherwise.
3082 * From unmanaged code you'll usually use the
3083 * mono_runtime_invoke() variant.
3085 * Note that this function doesn't handle virtual methods for
3086 * you, it will exec the exact method you pass: we still need to
3087 * expose a function to lookup the derived class implementation
3088 * of a virtual method (there are examples of this in the code,
3091 * If an exception is thrown, you can't use the MonoObject* result
3092 * from the function.
3094 * If this method cannot be invoked, @error will be set. If the
3095 * method throws an exception (and we're in coop mode) the exception
3096 * will be set in @error.
3098 * If the method returns a value type, it is boxed in an object
3102 mono_runtime_invoke_checked (MonoMethod *method, void *obj, void **params, MonoError* error)
3104 MONO_REQ_GC_UNSAFE_MODE;
3106 if (mono_runtime_get_no_exec ())
3107 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
3109 return do_runtime_invoke (method, obj, params, NULL, error);
3113 * mono_method_get_unmanaged_thunk:
3114 * @method: method to generate a thunk for.
3116 * Returns an unmanaged->managed thunk that can be used to call
3117 * a managed method directly from C.
3119 * The thunk's C signature closely matches the managed signature:
3121 * C#: public bool Equals (object obj);
3122 * C: typedef MonoBoolean (*Equals)(MonoObject*,
3123 * MonoObject*, MonoException**);
3125 * The 1st ("this") parameter must not be used with static methods:
3127 * C#: public static bool ReferenceEquals (object a, object b);
3128 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
3131 * The last argument must be a non-null pointer of a MonoException* pointer.
3132 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
3133 * exception has been thrown in managed code. Otherwise it will point
3134 * to the MonoException* caught by the thunk. In this case, the result of
3135 * the thunk is undefined:
3137 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
3138 * MonoException *ex = NULL;
3139 * Equals func = mono_method_get_unmanaged_thunk (method);
3140 * MonoBoolean res = func (thisObj, objToCompare, &ex);
3142 * // handle exception
3145 * The calling convention of the thunk matches the platform's default
3146 * convention. This means that under Windows, C declarations must
3147 * contain the __stdcall attribute:
3149 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
3150 * MonoObject*, MonoException**);
3154 * Value type arguments and return values are treated as they were objects:
3156 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
3157 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
3159 * Arguments must be properly boxed upon trunk's invocation, while return
3160 * values must be unboxed.
3163 mono_method_get_unmanaged_thunk (MonoMethod *method)
3165 MONO_REQ_GC_NEUTRAL_MODE;
3166 MONO_REQ_API_ENTRYPOINT;
3171 g_assert (!mono_threads_is_coop_enabled ());
3173 MONO_ENTER_GC_UNSAFE;
3174 method = mono_marshal_get_thunk_invoke_wrapper (method);
3175 res = mono_compile_method_checked (method, &error);
3176 mono_error_cleanup (&error);
3177 MONO_EXIT_GC_UNSAFE;
3183 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
3185 MONO_REQ_GC_UNSAFE_MODE;
3189 /* object fields cannot be byref, so we don't need a
3191 gpointer *p = (gpointer*)dest;
3198 case MONO_TYPE_BOOLEAN:
3200 case MONO_TYPE_U1: {
3201 guint8 *p = (guint8*)dest;
3202 *p = value ? *(guint8*)value : 0;
3207 case MONO_TYPE_CHAR: {
3208 guint16 *p = (guint16*)dest;
3209 *p = value ? *(guint16*)value : 0;
3212 #if SIZEOF_VOID_P == 4
3217 case MONO_TYPE_U4: {
3218 gint32 *p = (gint32*)dest;
3219 *p = value ? *(gint32*)value : 0;
3222 #if SIZEOF_VOID_P == 8
3227 case MONO_TYPE_U8: {
3228 gint64 *p = (gint64*)dest;
3229 *p = value ? *(gint64*)value : 0;
3232 case MONO_TYPE_R4: {
3233 float *p = (float*)dest;
3234 *p = value ? *(float*)value : 0;
3237 case MONO_TYPE_R8: {
3238 double *p = (double*)dest;
3239 *p = value ? *(double*)value : 0;
3242 case MONO_TYPE_STRING:
3243 case MONO_TYPE_SZARRAY:
3244 case MONO_TYPE_CLASS:
3245 case MONO_TYPE_OBJECT:
3246 case MONO_TYPE_ARRAY:
3247 mono_gc_wbarrier_generic_store (dest, deref_pointer ? *(MonoObject **)value : (MonoObject *)value);
3249 case MONO_TYPE_FNPTR:
3250 case MONO_TYPE_PTR: {
3251 gpointer *p = (gpointer*)dest;
3252 *p = deref_pointer? *(gpointer*)value: value;
3255 case MONO_TYPE_VALUETYPE:
3256 /* note that 't' and 'type->type' can be different */
3257 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3258 t = mono_class_enum_basetype (type->data.klass)->type;
3261 MonoClass *klass = mono_class_from_mono_type (type);
3262 int size = mono_class_value_size (klass, NULL);
3264 mono_gc_bzero_atomic (dest, size);
3266 mono_gc_wbarrier_value_copy (dest, value, 1, klass);
3269 case MONO_TYPE_GENERICINST:
3270 t = type->data.generic_class->container_class->byval_arg.type;
3273 g_error ("got type %x", type->type);
3278 * mono_field_set_value:
3279 * @obj: Instance object
3280 * @field: MonoClassField describing the field to set
3281 * @value: The value to be set
3283 * Sets the value of the field described by @field in the object instance @obj
3284 * to the value passed in @value. This method should only be used for instance
3285 * fields. For static fields, use mono_field_static_set_value.
3287 * The value must be on the native format of the field type.
3290 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3292 MONO_REQ_GC_UNSAFE_MODE;
3296 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3298 dest = (char*)obj + field->offset;
3299 mono_copy_value (field->type, dest, value, FALSE);
3303 * mono_field_static_set_value:
3304 * @field: MonoClassField describing the field to set
3305 * @value: The value to be set
3307 * Sets the value of the static field described by @field
3308 * to the value passed in @value.
3310 * The value must be on the native format of the field type.
3313 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3315 MONO_REQ_GC_UNSAFE_MODE;
3319 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3320 /* you cant set a constant! */
3321 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3323 if (field->offset == -1) {
3324 /* Special static */
3327 mono_domain_lock (vt->domain);
3328 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3329 mono_domain_unlock (vt->domain);
3330 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3332 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3334 mono_copy_value (field->type, dest, value, FALSE);
3338 * mono_vtable_get_static_field_data:
3340 * Internal use function: return a pointer to the memory holding the static fields
3341 * for a class or NULL if there are no static fields.
3342 * This is exported only for use by the debugger.
3345 mono_vtable_get_static_field_data (MonoVTable *vt)
3347 MONO_REQ_GC_NEUTRAL_MODE
3349 if (!vt->has_static_fields)
3351 return vt->vtable [vt->klass->vtable_size];
3355 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3357 MONO_REQ_GC_UNSAFE_MODE;
3361 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3362 if (field->offset == -1) {
3363 /* Special static */
3366 mono_domain_lock (vt->domain);
3367 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3368 mono_domain_unlock (vt->domain);
3369 src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3371 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3374 src = (guint8*)obj + field->offset;
3381 * mono_field_get_value:
3382 * @obj: Object instance
3383 * @field: MonoClassField describing the field to fetch information from
3384 * @value: pointer to the location where the value will be stored
3386 * Use this routine to get the value of the field @field in the object
3389 * The pointer provided by value must be of the field type, for reference
3390 * types this is a MonoObject*, for value types its the actual pointer to
3395 * mono_field_get_value (obj, int_field, &i);
3398 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3400 MONO_REQ_GC_UNSAFE_MODE;
3406 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3408 src = (char*)obj + field->offset;
3409 mono_copy_value (field->type, value, src, TRUE);
3413 * mono_field_get_value_object:
3414 * @domain: domain where the object will be created (if boxing)
3415 * @field: MonoClassField describing the field to fetch information from
3416 * @obj: The object instance for the field.
3418 * Returns: a new MonoObject with the value from the given field. If the
3419 * field represents a value type, the value is boxed.
3423 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3426 MonoObject* result = mono_field_get_value_object_checked (domain, field, obj, &error);
3427 mono_error_assert_ok (&error);
3432 * mono_field_get_value_object_checked:
3433 * @domain: domain where the object will be created (if boxing)
3434 * @field: MonoClassField describing the field to fetch information from
3435 * @obj: The object instance for the field.
3436 * @error: Set on error.
3438 * Returns: a new MonoObject with the value from the given field. If the
3439 * field represents a value type, the value is boxed. On error returns NULL and sets @error.
3443 mono_field_get_value_object_checked (MonoDomain *domain, MonoClassField *field, MonoObject *obj, MonoError *error)
3445 MONO_REQ_GC_UNSAFE_MODE;
3447 mono_error_init (error);
3451 MonoVTable *vtable = NULL;
3453 gboolean is_static = FALSE;
3454 gboolean is_ref = FALSE;
3455 gboolean is_literal = FALSE;
3456 gboolean is_ptr = FALSE;
3457 MonoType *type = mono_field_get_type_checked (field, error);
3459 return_val_if_nok (error, NULL);
3461 switch (type->type) {
3462 case MONO_TYPE_STRING:
3463 case MONO_TYPE_OBJECT:
3464 case MONO_TYPE_CLASS:
3465 case MONO_TYPE_ARRAY:
3466 case MONO_TYPE_SZARRAY:
3471 case MONO_TYPE_BOOLEAN:
3474 case MONO_TYPE_CHAR:
3483 case MONO_TYPE_VALUETYPE:
3484 is_ref = type->byref;
3486 case MONO_TYPE_GENERICINST:
3487 is_ref = !mono_type_generic_inst_is_valuetype (type);
3493 g_error ("type 0x%x not handled in "
3494 "mono_field_get_value_object", type->type);
3498 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3501 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3505 vtable = mono_class_vtable_full (domain, field->parent, error);
3506 return_val_if_nok (error, NULL);
3508 if (!vtable->initialized) {
3509 mono_runtime_class_init_full (vtable, error);
3510 return_val_if_nok (error, NULL);
3519 get_default_field_value (domain, field, &o, error);
3520 return_val_if_nok (error, NULL);
3521 } else if (is_static) {
3522 mono_field_static_get_value_checked (vtable, field, &o, error);
3523 return_val_if_nok (error, NULL);
3525 mono_field_get_value (obj, field, &o);
3531 static MonoMethod *m;
3537 MonoClass *ptr_klass = mono_class_get_pointer_class ();
3538 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3544 get_default_field_value (domain, field, v, error);
3545 return_val_if_nok (error, NULL);
3546 } else if (is_static) {
3547 mono_field_static_get_value_checked (vtable, field, v, error);
3548 return_val_if_nok (error, NULL);
3550 mono_field_get_value (obj, field, v);
3553 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3554 args [0] = ptr ? *ptr : NULL;
3555 args [1] = mono_type_get_object_checked (mono_domain_get (), type, error);
3556 return_val_if_nok (error, NULL);
3558 o = mono_runtime_invoke_checked (m, NULL, args, error);
3559 return_val_if_nok (error, NULL);
3564 /* boxed value type */
3565 klass = mono_class_from_mono_type (type);
3567 if (mono_class_is_nullable (klass))
3568 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass, error);
3570 o = mono_object_new_checked (domain, klass, error);
3571 return_val_if_nok (error, NULL);
3572 v = ((gchar *) o) + sizeof (MonoObject);
3575 get_default_field_value (domain, field, v, error);
3576 return_val_if_nok (error, NULL);
3577 } else if (is_static) {
3578 mono_field_static_get_value_checked (vtable, field, v, error);
3579 return_val_if_nok (error, NULL);
3581 mono_field_get_value (obj, field, v);
3588 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value, MonoError *error)
3590 MONO_REQ_GC_UNSAFE_MODE;
3592 mono_error_init (error);
3594 const char *p = blob;
3595 mono_metadata_decode_blob_size (p, &p);
3598 case MONO_TYPE_BOOLEAN:
3601 *(guint8 *) value = *p;
3603 case MONO_TYPE_CHAR:
3606 *(guint16*) value = read16 (p);
3610 *(guint32*) value = read32 (p);
3614 *(guint64*) value = read64 (p);
3617 readr4 (p, (float*) value);
3620 readr8 (p, (double*) value);
3622 case MONO_TYPE_STRING:
3623 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob, error);
3625 case MONO_TYPE_CLASS:
3626 *(gpointer*) value = NULL;
3630 g_warning ("type 0x%02x should not be in constant table", type);
3636 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error)
3638 MONO_REQ_GC_NEUTRAL_MODE;
3640 MonoTypeEnum def_type;
3643 mono_error_init (error);
3645 data = mono_class_get_field_default_value (field, &def_type);
3646 mono_get_constant_value_from_blob (domain, def_type, data, value, error);
3650 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3652 MONO_REQ_GC_UNSAFE_MODE;
3656 mono_error_init (error);
3658 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3660 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3661 get_default_field_value (vt->domain, field, value, error);
3665 if (field->offset == -1) {
3666 /* Special static */
3667 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3668 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3670 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3672 mono_copy_value (field->type, value, src, TRUE);
3676 * mono_field_static_get_value:
3677 * @vt: vtable to the object
3678 * @field: MonoClassField describing the field to fetch information from
3679 * @value: where the value is returned
3681 * Use this routine to get the value of the static field @field value.
3683 * The pointer provided by value must be of the field type, for reference
3684 * types this is a MonoObject*, for value types its the actual pointer to
3689 * mono_field_static_get_value (vt, int_field, &i);
3692 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3694 MONO_REQ_GC_NEUTRAL_MODE;
3697 mono_field_static_get_value_checked (vt, field, value, &error);
3698 mono_error_cleanup (&error);
3702 * mono_field_static_get_value_checked:
3703 * @vt: vtable to the object
3704 * @field: MonoClassField describing the field to fetch information from
3705 * @value: where the value is returned
3706 * @error: set on error
3708 * Use this routine to get the value of the static field @field value.
3710 * The pointer provided by value must be of the field type, for reference
3711 * types this is a MonoObject*, for value types its the actual pointer to
3716 * mono_field_static_get_value_checked (vt, int_field, &i, error);
3717 * if (!is_ok (error)) { ... }
3719 * On failure sets @error.
3722 mono_field_static_get_value_checked (MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3724 MONO_REQ_GC_NEUTRAL_MODE;
3726 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value, error);
3730 * mono_property_set_value:
3731 * @prop: MonoProperty to set
3732 * @obj: instance object on which to act
3733 * @params: parameters to pass to the propery
3734 * @exc: optional exception
3736 * Invokes the property's set method with the given arguments on the
3737 * object instance obj (or NULL for static properties).
3739 * You can pass NULL as the exc argument if you don't want to
3740 * catch exceptions, otherwise, *exc will be set to the exception
3741 * thrown, if any. if an exception is thrown, you can't use the
3742 * MonoObject* result from the function.
3745 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3747 MONO_REQ_GC_UNSAFE_MODE;
3750 do_runtime_invoke (prop->set, obj, params, exc, &error);
3751 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3752 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3754 mono_error_cleanup (&error);
3759 * mono_property_set_value_checked:
3760 * @prop: MonoProperty to set
3761 * @obj: instance object on which to act
3762 * @params: parameters to pass to the propery
3763 * @error: set on error
3765 * Invokes the property's set method with the given arguments on the
3766 * object instance obj (or NULL for static properties).
3768 * Returns: TRUE on success. On failure returns FALSE and sets @error.
3769 * If an exception is thrown, it will be caught and returned via @error.
3772 mono_property_set_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3774 MONO_REQ_GC_UNSAFE_MODE;
3778 mono_error_init (error);
3779 do_runtime_invoke (prop->set, obj, params, &exc, error);
3780 if (exc != NULL && is_ok (error))
3781 mono_error_set_exception_instance (error, (MonoException*)exc);
3782 return is_ok (error);
3786 * mono_property_get_value:
3787 * @prop: MonoProperty to fetch
3788 * @obj: instance object on which to act
3789 * @params: parameters to pass to the propery
3790 * @exc: optional exception
3792 * Invokes the property's get method with the given arguments on the
3793 * object instance obj (or NULL for static properties).
3795 * You can pass NULL as the exc argument if you don't want to
3796 * catch exceptions, otherwise, *exc will be set to the exception
3797 * thrown, if any. if an exception is thrown, you can't use the
3798 * MonoObject* result from the function.
3800 * Returns: the value from invoking the get method on the property.
3803 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3805 MONO_REQ_GC_UNSAFE_MODE;
3808 MonoObject *val = do_runtime_invoke (prop->get, obj, params, exc, &error);
3809 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3810 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3812 mono_error_cleanup (&error); /* FIXME don't raise here */
3819 * mono_property_get_value_checked:
3820 * @prop: MonoProperty to fetch
3821 * @obj: instance object on which to act
3822 * @params: parameters to pass to the propery
3823 * @error: set on error
3825 * Invokes the property's get method with the given arguments on the
3826 * object instance obj (or NULL for static properties).
3828 * If an exception is thrown, you can't use the
3829 * MonoObject* result from the function. The exception will be propagated via @error.
3831 * Returns: the value from invoking the get method on the property. On
3832 * failure returns NULL and sets @error.
3835 mono_property_get_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3837 MONO_REQ_GC_UNSAFE_MODE;
3840 MonoObject *val = do_runtime_invoke (prop->get, obj, params, &exc, error);
3841 if (exc != NULL && !is_ok (error))
3842 mono_error_set_exception_instance (error, (MonoException*) exc);
3850 * mono_nullable_init:
3851 * @buf: The nullable structure to initialize.
3852 * @value: the value to initialize from
3853 * @klass: the type for the object
3855 * Initialize the nullable structure pointed to by @buf from @value which
3856 * should be a boxed value type. The size of @buf should be able to hold
3857 * as much data as the @klass->instance_size (which is the number of bytes
3858 * that will be copies).
3860 * Since Nullables have variable structure, we can not define a C
3861 * structure for them.
3864 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3866 MONO_REQ_GC_UNSAFE_MODE;
3868 MonoClass *param_class = klass->cast_class;
3870 mono_class_setup_fields_locking (klass);
3871 g_assert (klass->fields_inited);
3873 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3874 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3876 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3878 if (param_class->has_references)
3879 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3881 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3883 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3888 * mono_nullable_box:
3889 * @buf: The buffer representing the data to be boxed
3890 * @klass: the type to box it as.
3891 * @error: set on oerr
3893 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3894 * @buf. On failure returns NULL and sets @error
3897 mono_nullable_box (guint8 *buf, MonoClass *klass, MonoError *error)
3899 MONO_REQ_GC_UNSAFE_MODE;
3901 mono_error_init (error);
3902 MonoClass *param_class = klass->cast_class;
3904 mono_class_setup_fields_locking (klass);
3905 g_assert (klass->fields_inited);
3907 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3908 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3910 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3911 MonoObject *o = mono_object_new_checked (mono_domain_get (), param_class, error);
3912 return_val_if_nok (error, NULL);
3913 if (param_class->has_references)
3914 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3916 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3924 * mono_get_delegate_invoke:
3925 * @klass: The delegate class
3927 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3930 mono_get_delegate_invoke (MonoClass *klass)
3932 MONO_REQ_GC_NEUTRAL_MODE;
3936 /* This is called at runtime, so avoid the slower search in metadata */
3937 mono_class_setup_methods (klass);
3938 if (mono_class_has_failure (klass))
3940 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3945 * mono_get_delegate_begin_invoke:
3946 * @klass: The delegate class
3948 * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3951 mono_get_delegate_begin_invoke (MonoClass *klass)
3953 MONO_REQ_GC_NEUTRAL_MODE;
3957 /* This is called at runtime, so avoid the slower search in metadata */
3958 mono_class_setup_methods (klass);
3959 if (mono_class_has_failure (klass))
3961 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3966 * mono_get_delegate_end_invoke:
3967 * @klass: The delegate class
3969 * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3972 mono_get_delegate_end_invoke (MonoClass *klass)
3974 MONO_REQ_GC_NEUTRAL_MODE;
3978 /* This is called at runtime, so avoid the slower search in metadata */
3979 mono_class_setup_methods (klass);
3980 if (mono_class_has_failure (klass))
3982 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3987 * mono_runtime_delegate_invoke:
3988 * @delegate: pointer to a delegate object.
3989 * @params: parameters for the delegate.
3990 * @exc: Pointer to the exception result.
3992 * Invokes the delegate method @delegate with the parameters provided.
3994 * You can pass NULL as the exc argument if you don't want to
3995 * catch exceptions, otherwise, *exc will be set to the exception
3996 * thrown, if any. if an exception is thrown, you can't use the
3997 * MonoObject* result from the function.
4000 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
4002 MONO_REQ_GC_UNSAFE_MODE;
4006 MonoObject *result = mono_runtime_delegate_try_invoke (delegate, params, exc, &error);
4008 mono_error_cleanup (&error);
4011 if (!is_ok (&error))
4012 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
4016 MonoObject *result = mono_runtime_delegate_invoke_checked (delegate, params, &error);
4017 mono_error_raise_exception (&error); /* FIXME don't raise here */
4023 * mono_runtime_delegate_try_invoke:
4024 * @delegate: pointer to a delegate object.
4025 * @params: parameters for the delegate.
4026 * @exc: Pointer to the exception result.
4027 * @error: set on error
4029 * Invokes the delegate method @delegate with the parameters provided.
4031 * You can pass NULL as the exc argument if you don't want to
4032 * catch exceptions, otherwise, *exc will be set to the exception
4033 * thrown, if any. On failure to execute, @error will be set.
4034 * if an exception is thrown, you can't use the
4035 * MonoObject* result from the function.
4038 mono_runtime_delegate_try_invoke (MonoObject *delegate, void **params, MonoObject **exc, MonoError *error)
4040 MONO_REQ_GC_UNSAFE_MODE;
4042 mono_error_init (error);
4044 MonoClass *klass = delegate->vtable->klass;
4047 im = mono_get_delegate_invoke (klass);
4049 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
4052 o = mono_runtime_try_invoke (im, delegate, params, exc, error);
4054 o = mono_runtime_invoke_checked (im, delegate, params, error);
4061 * mono_runtime_delegate_invoke_checked:
4062 * @delegate: pointer to a delegate object.
4063 * @params: parameters for the delegate.
4064 * @error: set on error
4066 * Invokes the delegate method @delegate with the parameters provided.
4068 * On failure @error will be set and you can't use the MonoObject*
4069 * result from the function.
4072 mono_runtime_delegate_invoke_checked (MonoObject *delegate, void **params, MonoError *error)
4074 mono_error_init (error);
4075 return mono_runtime_delegate_try_invoke (delegate, params, NULL, error);
4078 static char **main_args = NULL;
4079 static int num_main_args = 0;
4082 * mono_runtime_get_main_args:
4084 * Returns: a MonoArray with the arguments passed to the main program
4087 mono_runtime_get_main_args (void)
4089 MONO_REQ_GC_UNSAFE_MODE;
4091 MonoArray *result = mono_runtime_get_main_args_checked (&error);
4092 mono_error_assert_ok (&error);
4097 * mono_runtime_get_main_args:
4098 * @error: set on error
4100 * Returns: a MonoArray with the arguments passed to the main
4101 * program. On failure returns NULL and sets @error.
4104 mono_runtime_get_main_args_checked (MonoError *error)
4108 MonoDomain *domain = mono_domain_get ();
4110 mono_error_init (error);
4112 res = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, num_main_args, error);
4113 return_val_if_nok (error, NULL);
4115 for (i = 0; i < num_main_args; ++i)
4116 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
4122 free_main_args (void)
4124 MONO_REQ_GC_NEUTRAL_MODE;
4128 for (i = 0; i < num_main_args; ++i)
4129 g_free (main_args [i]);
4136 * mono_runtime_set_main_args:
4137 * @argc: number of arguments from the command line
4138 * @argv: array of strings from the command line
4140 * Set the command line arguments from an embedding application that doesn't otherwise call
4141 * mono_runtime_run_main ().
4144 mono_runtime_set_main_args (int argc, char* argv[])
4146 MONO_REQ_GC_NEUTRAL_MODE;
4151 main_args = g_new0 (char*, argc);
4152 num_main_args = argc;
4154 for (i = 0; i < argc; ++i) {
4157 utf8_arg = mono_utf8_from_external (argv[i]);
4158 if (utf8_arg == NULL) {
4159 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
4160 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4164 main_args [i] = utf8_arg;
4171 * mono_runtime_run_main:
4172 * @method: the method to start the application with (usually Main)
4173 * @argc: number of arguments from the command line
4174 * @argv: array of strings from the command line
4175 * @exc: excetption results
4177 * Execute a standard Main() method (argc/argv contains the
4178 * executable name). This method also sets the command line argument value
4179 * needed by System.Environment.
4184 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
4187 MONO_REQ_GC_UNSAFE_MODE;
4191 MonoArray *args = NULL;
4192 MonoDomain *domain = mono_domain_get ();
4193 gchar *utf8_fullpath;
4194 MonoMethodSignature *sig;
4196 g_assert (method != NULL);
4198 mono_thread_set_main (mono_thread_current ());
4200 main_args = g_new0 (char*, argc);
4201 num_main_args = argc;
4203 if (!g_path_is_absolute (argv [0])) {
4204 gchar *basename = g_path_get_basename (argv [0]);
4205 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
4209 utf8_fullpath = mono_utf8_from_external (fullpath);
4210 if(utf8_fullpath == NULL) {
4211 /* Printing the arg text will cause glib to
4212 * whinge about "Invalid UTF-8", but at least
4213 * its relevant, and shows the problem text
4216 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
4217 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4224 utf8_fullpath = mono_utf8_from_external (argv[0]);
4225 if(utf8_fullpath == NULL) {
4226 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
4227 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4232 main_args [0] = utf8_fullpath;
4234 for (i = 1; i < argc; ++i) {
4237 utf8_arg=mono_utf8_from_external (argv[i]);
4238 if(utf8_arg==NULL) {
4239 /* Ditto the comment about Invalid UTF-8 here */
4240 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
4241 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4245 main_args [i] = utf8_arg;
4250 sig = mono_method_signature (method);
4252 g_print ("Unable to load Main method.\n");
4256 if (sig->param_count) {
4257 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, argc, &error);
4258 mono_error_assert_ok (&error);
4259 for (i = 0; i < argc; ++i) {
4260 /* The encodings should all work, given that
4261 * we've checked all these args for the
4264 gchar *str = mono_utf8_from_external (argv [i]);
4265 MonoString *arg = mono_string_new (domain, str);
4266 mono_array_setref (args, i, arg);
4270 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, 0, &error);
4271 mono_error_assert_ok (&error);
4274 mono_assembly_set_main (method->klass->image->assembly);
4276 return mono_runtime_exec_main (method, args, exc);
4280 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4282 static MonoMethod *serialize_method;
4288 if (!serialize_method) {
4289 MonoClass *klass = mono_class_get_remoting_services_class ();
4290 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
4293 if (!serialize_method) {
4298 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
4303 array = mono_runtime_try_invoke (serialize_method, NULL, params, exc, &error);
4304 if (*exc == NULL && !mono_error_ok (&error))
4305 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert serialize_object to MonoError */
4307 mono_error_cleanup (&error);
4316 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4318 MONO_REQ_GC_UNSAFE_MODE;
4320 static MonoMethod *deserialize_method;
4326 if (!deserialize_method) {
4327 MonoClass *klass = mono_class_get_remoting_services_class ();
4328 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
4330 if (!deserialize_method) {
4338 result = mono_runtime_try_invoke (deserialize_method, NULL, params, exc, &error);
4339 if (*exc == NULL && !mono_error_ok (&error))
4340 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert deserialize_object to MonoError */
4342 mono_error_cleanup (&error);
4350 #ifndef DISABLE_REMOTING
4352 make_transparent_proxy (MonoObject *obj, MonoError *error)
4354 MONO_REQ_GC_UNSAFE_MODE;
4356 static MonoMethod *get_proxy_method;
4358 MonoDomain *domain = mono_domain_get ();
4359 MonoRealProxy *real_proxy;
4360 MonoReflectionType *reflection_type;
4361 MonoTransparentProxy *transparent_proxy;
4363 mono_error_init (error);
4365 if (!get_proxy_method)
4366 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
4368 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
4370 real_proxy = (MonoRealProxy*) mono_object_new_checked (domain, mono_defaults.real_proxy_class, error);
4371 return_val_if_nok (error, NULL);
4372 reflection_type = mono_type_get_object_checked (domain, &obj->vtable->klass->byval_arg, error);
4373 return_val_if_nok (error, NULL);
4375 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
4376 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
4378 MonoObject *exc = NULL;
4380 transparent_proxy = (MonoTransparentProxy*) mono_runtime_try_invoke (get_proxy_method, real_proxy, NULL, &exc, error);
4381 if (exc != NULL && is_ok (error))
4382 mono_error_set_exception_instance (error, (MonoException*)exc);
4384 return (MonoObject*) transparent_proxy;
4386 #endif /* DISABLE_REMOTING */
4389 * mono_object_xdomain_representation
4391 * @target_domain: a domain
4392 * @error: set on error.
4394 * Creates a representation of obj in the domain target_domain. This
4395 * is either a copy of obj arrived through via serialization and
4396 * deserialization or a proxy, depending on whether the object is
4397 * serializable or marshal by ref. obj must not be in target_domain.
4399 * If the object cannot be represented in target_domain, NULL is
4400 * returned and @error is set appropriately.
4403 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoError *error)
4405 MONO_REQ_GC_UNSAFE_MODE;
4407 mono_error_init (error);
4408 MonoObject *deserialized = NULL;
4410 #ifndef DISABLE_REMOTING
4411 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
4412 deserialized = make_transparent_proxy (obj, error);
4417 gboolean failure = FALSE;
4418 MonoDomain *domain = mono_domain_get ();
4419 MonoObject *serialized;
4420 MonoObject *exc = NULL;
4422 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
4423 serialized = serialize_object (obj, &failure, &exc);
4424 mono_domain_set_internal_with_options (target_domain, FALSE);
4426 deserialized = deserialize_object (serialized, &failure, &exc);
4427 if (domain != target_domain)
4428 mono_domain_set_internal_with_options (domain, FALSE);
4430 mono_error_set_exception_instance (error, (MonoException*)exc);
4433 return deserialized;
4436 /* Used in call_unhandled_exception_delegate */
4438 create_unhandled_exception_eventargs (MonoObject *exc, MonoError *error)
4440 MONO_REQ_GC_UNSAFE_MODE;
4442 mono_error_init (error);
4445 MonoMethod *method = NULL;
4446 MonoBoolean is_terminating = TRUE;
4449 klass = mono_class_get_unhandled_exception_event_args_class ();
4450 mono_class_init (klass);
4452 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4453 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
4457 args [1] = &is_terminating;
4459 obj = mono_object_new_checked (mono_domain_get (), klass, error);
4460 return_val_if_nok (error, NULL);
4462 mono_runtime_invoke_checked (method, obj, args, error);
4463 return_val_if_nok (error, NULL);
4468 /* Used in mono_unhandled_exception */
4470 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4471 MONO_REQ_GC_UNSAFE_MODE;
4474 MonoObject *e = NULL;
4476 MonoDomain *current_domain = mono_domain_get ();
4478 if (domain != current_domain)
4479 mono_domain_set_internal_with_options (domain, FALSE);
4481 g_assert (domain == mono_object_domain (domain->domain));
4483 if (mono_object_domain (exc) != domain) {
4485 exc = mono_object_xdomain_representation (exc, domain, &error);
4487 if (!is_ok (&error)) {
4488 MonoError inner_error;
4489 MonoException *serialization_exc = mono_error_convert_to_exception (&error);
4490 exc = mono_object_xdomain_representation ((MonoObject*)serialization_exc, domain, &inner_error);
4491 mono_error_assert_ok (&inner_error);
4493 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4494 "System.Runtime.Serialization", "SerializationException",
4495 "Could not serialize unhandled exception.");
4499 g_assert (mono_object_domain (exc) == domain);
4501 pa [0] = domain->domain;
4502 pa [1] = create_unhandled_exception_eventargs (exc, &error);
4503 mono_error_assert_ok (&error);
4504 mono_runtime_delegate_try_invoke (delegate, pa, &e, &error);
4505 if (!is_ok (&error)) {
4507 e = (MonoObject*)mono_error_convert_to_exception (&error);
4509 mono_error_cleanup (&error);
4512 if (domain != current_domain)
4513 mono_domain_set_internal_with_options (current_domain, FALSE);
4516 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4517 if (!mono_error_ok (&error)) {
4518 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4519 mono_error_cleanup (&error);
4521 g_warning ("exception inside UnhandledException handler: %s\n", msg);
4527 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4530 * mono_runtime_unhandled_exception_policy_set:
4531 * @policy: the new policy
4533 * This is a VM internal routine.
4535 * Sets the runtime policy for handling unhandled exceptions.
4538 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4539 runtime_unhandled_exception_policy = policy;
4543 * mono_runtime_unhandled_exception_policy_get:
4545 * This is a VM internal routine.
4547 * Gets the runtime policy for handling unhandled exceptions.
4549 MonoRuntimeUnhandledExceptionPolicy
4550 mono_runtime_unhandled_exception_policy_get (void) {
4551 return runtime_unhandled_exception_policy;
4555 * mono_unhandled_exception:
4556 * @exc: exception thrown
4558 * This is a VM internal routine.
4560 * We call this function when we detect an unhandled exception
4561 * in the default domain.
4563 * It invokes the * UnhandledException event in AppDomain or prints
4564 * a warning to the console
4567 mono_unhandled_exception (MonoObject *exc)
4569 MONO_REQ_GC_UNSAFE_MODE;
4572 MonoClassField *field;
4573 MonoDomain *current_domain, *root_domain;
4574 MonoObject *current_appdomain_delegate = NULL, *root_appdomain_delegate = NULL;
4576 if (mono_class_has_parent (exc->vtable->klass, mono_defaults.threadabortexception_class))
4579 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4582 current_domain = mono_domain_get ();
4583 root_domain = mono_get_root_domain ();
4585 root_appdomain_delegate = mono_field_get_value_object_checked (root_domain, field, (MonoObject*) root_domain->domain, &error);
4586 mono_error_assert_ok (&error);
4587 if (current_domain != root_domain) {
4588 current_appdomain_delegate = mono_field_get_value_object_checked (current_domain, field, (MonoObject*) current_domain->domain, &error);
4589 mono_error_assert_ok (&error);
4592 if (!current_appdomain_delegate && !root_appdomain_delegate) {
4593 mono_print_unhandled_exception (exc);
4595 if (root_appdomain_delegate)
4596 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4597 if (current_appdomain_delegate)
4598 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4601 /* set exitcode only if we will abort the process */
4602 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4603 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4605 mono_environment_exitcode_set (1);
4610 * mono_runtime_exec_managed_code:
4611 * @domain: Application domain
4612 * @main_func: function to invoke from the execution thread
4613 * @main_args: parameter to the main_func
4615 * Launch a new thread to execute a function
4617 * main_func is called back from the thread with main_args as the
4618 * parameter. The callback function is expected to start Main()
4619 * eventually. This function then waits for all managed threads to
4621 * It is not necesseray anymore to execute managed code in a subthread,
4622 * so this function should not be used anymore by default: just
4623 * execute the code and then call mono_thread_manage ().
4626 mono_runtime_exec_managed_code (MonoDomain *domain,
4627 MonoMainThreadFunc main_func,
4631 mono_thread_create_checked (domain, main_func, main_args, &error);
4632 mono_error_assert_ok (&error);
4634 mono_thread_manage ();
4638 * Execute a standard Main() method (args doesn't contain the
4642 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4644 MONO_REQ_GC_UNSAFE_MODE;
4650 MonoCustomAttrInfo* cinfo;
4651 gboolean has_stathread_attribute;
4652 MonoInternalThread* thread = mono_thread_internal_current ();
4658 domain = mono_object_domain (args);
4659 if (!domain->entry_assembly) {
4661 MonoAssembly *assembly;
4663 assembly = method->klass->image->assembly;
4664 domain->entry_assembly = assembly;
4665 /* Domains created from another domain already have application_base and configuration_file set */
4666 if (domain->setup->application_base == NULL) {
4667 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4670 if (domain->setup->configuration_file == NULL) {
4671 str = g_strconcat (assembly->image->name, ".config", NULL);
4672 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4674 mono_domain_set_options_from_config (domain);
4678 cinfo = mono_custom_attrs_from_method_checked (method, &error);
4679 mono_error_cleanup (&error); /* FIXME warn here? */
4681 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, mono_class_get_sta_thread_attribute_class ());
4683 mono_custom_attrs_free (cinfo);
4685 has_stathread_attribute = FALSE;
4687 if (has_stathread_attribute) {
4688 thread->apartment_state = ThreadApartmentState_STA;
4690 thread->apartment_state = ThreadApartmentState_MTA;
4692 mono_thread_init_apartment_state ();
4694 /* FIXME: check signature of method */
4695 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4698 res = mono_runtime_try_invoke (method, NULL, pa, exc, &error);
4699 if (*exc == NULL && !mono_error_ok (&error))
4700 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4702 mono_error_cleanup (&error);
4704 res = mono_runtime_invoke_checked (method, NULL, pa, &error);
4705 mono_error_raise_exception (&error); /* FIXME don't raise here */
4709 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4713 mono_environment_exitcode_set (rval);
4716 mono_runtime_try_invoke (method, NULL, pa, exc, &error);
4717 if (*exc == NULL && !mono_error_ok (&error))
4718 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4720 mono_error_cleanup (&error);
4722 mono_runtime_invoke_checked (method, NULL, pa, &error);
4723 mono_error_raise_exception (&error); /* FIXME don't raise here */
4729 /* If the return type of Main is void, only
4730 * set the exitcode if an exception was thrown
4731 * (we don't want to blow away an
4732 * explicitly-set exit code)
4735 mono_environment_exitcode_set (rval);
4742 /** invoke_array_extract_argument:
4743 * @params: array of arguments to the method.
4744 * @i: the index of the argument to extract.
4745 * @t: ith type from the method signature.
4746 * @has_byref_nullables: outarg - TRUE if method expects a byref nullable argument
4747 * @error: set on error.
4749 * Given an array of method arguments, return the ith one using the corresponding type
4750 * to perform necessary unboxing. If method expects a ref nullable argument, writes TRUE to @has_byref_nullables.
4752 * On failure sets @error and returns NULL.
4755 invoke_array_extract_argument (MonoArray *params, int i, MonoType *t, gboolean* has_byref_nullables, MonoError *error)
4757 MonoType *t_orig = t;
4758 gpointer result = NULL;
4759 mono_error_init (error);
4764 case MONO_TYPE_BOOLEAN:
4767 case MONO_TYPE_CHAR:
4776 case MONO_TYPE_VALUETYPE:
4777 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (t_orig))) {
4778 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4779 result = mono_array_get (params, MonoObject*, i);
4781 *has_byref_nullables = TRUE;
4783 /* MS seems to create the objects if a null is passed in */
4784 if (!mono_array_get (params, MonoObject*, i)) {
4785 MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (t_orig), error);
4786 return_val_if_nok (error, NULL);
4787 mono_array_setref (params, i, o);
4792 * We can't pass the unboxed vtype byref to the callee, since
4793 * that would mean the callee would be able to modify boxed
4794 * primitive types. So we (and MS) make a copy of the boxed
4795 * object, pass that to the callee, and replace the original
4796 * boxed object in the arg array with the copy.
4798 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4799 MonoObject *copy = mono_value_box_checked (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig), error);
4800 return_val_if_nok (error, NULL);
4801 mono_array_setref (params, i, copy);
4804 result = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4807 case MONO_TYPE_STRING:
4808 case MONO_TYPE_OBJECT:
4809 case MONO_TYPE_CLASS:
4810 case MONO_TYPE_ARRAY:
4811 case MONO_TYPE_SZARRAY:
4813 result = mono_array_addr (params, MonoObject*, i);
4814 // FIXME: I need to check this code path
4816 result = mono_array_get (params, MonoObject*, i);
4818 case MONO_TYPE_GENERICINST:
4820 t = &t->data.generic_class->container_class->this_arg;
4822 t = &t->data.generic_class->container_class->byval_arg;
4824 case MONO_TYPE_PTR: {
4827 /* The argument should be an IntPtr */
4828 arg = mono_array_get (params, MonoObject*, i);
4832 g_assert (arg->vtable->klass == mono_defaults.int_class);
4833 result = ((MonoIntPtr*)arg)->m_value;
4838 g_error ("type 0x%x not handled in mono_runtime_invoke_array", t_orig->type);
4843 * mono_runtime_invoke_array:
4844 * @method: method to invoke
4845 * @obJ: object instance
4846 * @params: arguments to the method
4847 * @exc: exception information.
4849 * Invokes the method represented by @method on the object @obj.
4851 * obj is the 'this' pointer, it should be NULL for static
4852 * methods, a MonoObject* for object instances and a pointer to
4853 * the value type for value types.
4855 * The params array contains the arguments to the method with the
4856 * same convention: MonoObject* pointers for object instances and
4857 * pointers to the value type otherwise. The _invoke_array
4858 * variant takes a C# object[] as the params argument (MonoArray
4859 * *params): in this case the value types are boxed inside the
4860 * respective reference representation.
4862 * From unmanaged code you'll usually use the
4863 * mono_runtime_invoke_checked() variant.
4865 * Note that this function doesn't handle virtual methods for
4866 * you, it will exec the exact method you pass: we still need to
4867 * expose a function to lookup the derived class implementation
4868 * of a virtual method (there are examples of this in the code,
4871 * You can pass NULL as the exc argument if you don't want to
4872 * catch exceptions, otherwise, *exc will be set to the exception
4873 * thrown, if any. if an exception is thrown, you can't use the
4874 * MonoObject* result from the function.
4876 * If the method returns a value type, it is boxed in an object
4880 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4885 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, exc, &error);
4887 mono_error_cleanup (&error);
4890 if (!is_ok (&error))
4891 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
4895 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, NULL, &error);
4896 mono_error_raise_exception (&error); /* FIXME don't raise here */
4902 * mono_runtime_invoke_array_checked:
4903 * @method: method to invoke
4904 * @obJ: object instance
4905 * @params: arguments to the method
4906 * @error: set on failure.
4908 * Invokes the method represented by @method on the object @obj.
4910 * obj is the 'this' pointer, it should be NULL for static
4911 * methods, a MonoObject* for object instances and a pointer to
4912 * the value type for value types.
4914 * The params array contains the arguments to the method with the
4915 * same convention: MonoObject* pointers for object instances and
4916 * pointers to the value type otherwise. The _invoke_array
4917 * variant takes a C# object[] as the params argument (MonoArray
4918 * *params): in this case the value types are boxed inside the
4919 * respective reference representation.
4921 * From unmanaged code you'll usually use the
4922 * mono_runtime_invoke_checked() variant.
4924 * Note that this function doesn't handle virtual methods for
4925 * you, it will exec the exact method you pass: we still need to
4926 * expose a function to lookup the derived class implementation
4927 * of a virtual method (there are examples of this in the code,
4930 * On failure or exception, @error will be set. In that case, you
4931 * can't use the MonoObject* result from the function.
4933 * If the method returns a value type, it is boxed in an object
4937 mono_runtime_invoke_array_checked (MonoMethod *method, void *obj, MonoArray *params,
4940 mono_error_init (error);
4941 return mono_runtime_try_invoke_array (method, obj, params, NULL, error);
4945 * mono_runtime_try_invoke_array:
4946 * @method: method to invoke
4947 * @obJ: object instance
4948 * @params: arguments to the method
4949 * @exc: exception information.
4950 * @error: set on failure.
4952 * Invokes the method represented by @method on the object @obj.
4954 * obj is the 'this' pointer, it should be NULL for static
4955 * methods, a MonoObject* for object instances and a pointer to
4956 * the value type for value types.
4958 * The params array contains the arguments to the method with the
4959 * same convention: MonoObject* pointers for object instances and
4960 * pointers to the value type otherwise. The _invoke_array
4961 * variant takes a C# object[] as the params argument (MonoArray
4962 * *params): in this case the value types are boxed inside the
4963 * respective reference representation.
4965 * From unmanaged code you'll usually use the
4966 * mono_runtime_invoke_checked() variant.
4968 * Note that this function doesn't handle virtual methods for
4969 * you, it will exec the exact method you pass: we still need to
4970 * expose a function to lookup the derived class implementation
4971 * of a virtual method (there are examples of this in the code,
4974 * You can pass NULL as the exc argument if you don't want to catch
4975 * exceptions, otherwise, *exc will be set to the exception thrown, if
4976 * any. On other failures, @error will be set. If an exception is
4977 * thrown or there's an error, you can't use the MonoObject* result
4978 * from the function.
4980 * If the method returns a value type, it is boxed in an object
4984 mono_runtime_try_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4985 MonoObject **exc, MonoError *error)
4987 MONO_REQ_GC_UNSAFE_MODE;
4989 mono_error_init (error);
4991 MonoMethodSignature *sig = mono_method_signature (method);
4992 gpointer *pa = NULL;
4995 gboolean has_byref_nullables = FALSE;
4997 if (NULL != params) {
4998 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
4999 for (i = 0; i < mono_array_length (params); i++) {
5000 MonoType *t = sig->params [i];
5001 pa [i] = invoke_array_extract_argument (params, i, t, &has_byref_nullables, error);
5002 return_val_if_nok (error, NULL);
5006 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
5009 if (mono_class_is_nullable (method->klass)) {
5010 /* Need to create a boxed vtype instead */
5016 return mono_value_box_checked (mono_domain_get (), method->klass->cast_class, pa [0], error);
5021 obj = mono_object_new_checked (mono_domain_get (), method->klass, error);
5022 mono_error_assert_ok (error);
5023 g_assert (obj); /*maybe we should raise a TLE instead?*/
5024 #ifndef DISABLE_REMOTING
5025 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
5026 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
5029 if (method->klass->valuetype)
5030 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
5033 } else if (method->klass->valuetype) {
5034 obj = mono_value_box_checked (mono_domain_get (), method->klass, obj, error);
5035 return_val_if_nok (error, NULL);
5039 mono_runtime_try_invoke (method, o, pa, exc, error);
5041 mono_runtime_invoke_checked (method, o, pa, error);
5044 return (MonoObject *)obj;
5046 if (mono_class_is_nullable (method->klass)) {
5047 MonoObject *nullable;
5049 /* Convert the unboxed vtype into a Nullable structure */
5050 nullable = mono_object_new_checked (mono_domain_get (), method->klass, error);
5051 return_val_if_nok (error, NULL);
5053 MonoObject *boxed = mono_value_box_checked (mono_domain_get (), method->klass->cast_class, obj, error);
5054 return_val_if_nok (error, NULL);
5055 mono_nullable_init ((guint8 *)mono_object_unbox (nullable), boxed, method->klass);
5056 obj = mono_object_unbox (nullable);
5059 /* obj must be already unboxed if needed */
5061 res = mono_runtime_try_invoke (method, obj, pa, exc, error);
5063 res = mono_runtime_invoke_checked (method, obj, pa, error);
5065 return_val_if_nok (error, NULL);
5067 if (sig->ret->type == MONO_TYPE_PTR) {
5068 MonoClass *pointer_class;
5069 static MonoMethod *box_method;
5071 MonoObject *box_exc;
5074 * The runtime-invoke wrapper returns a boxed IntPtr, need to
5075 * convert it to a Pointer object.
5077 pointer_class = mono_class_get_pointer_class ();
5079 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
5081 g_assert (res->vtable->klass == mono_defaults.int_class);
5082 box_args [0] = ((MonoIntPtr*)res)->m_value;
5083 box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, error);
5084 return_val_if_nok (error, NULL);
5086 res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, error);
5087 g_assert (box_exc == NULL);
5088 mono_error_assert_ok (error);
5091 if (has_byref_nullables) {
5093 * The runtime invoke wrapper already converted byref nullables back,
5094 * and stored them in pa, we just need to copy them back to the
5097 for (i = 0; i < mono_array_length (params); i++) {
5098 MonoType *t = sig->params [i];
5100 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
5101 mono_array_setref (params, i, pa [i]);
5111 * @klass: the class of the object that we want to create
5113 * Returns: a newly created object whose definition is
5114 * looked up using @klass. This will not invoke any constructors,
5115 * so the consumer of this routine has to invoke any constructors on
5116 * its own to initialize the object.
5118 * It returns NULL on failure.
5121 mono_object_new (MonoDomain *domain, MonoClass *klass)
5123 MONO_REQ_GC_UNSAFE_MODE;
5127 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5129 mono_error_cleanup (&error);
5134 ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
5136 MONO_REQ_GC_UNSAFE_MODE;
5140 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5142 mono_error_set_pending_exception (&error);
5147 * mono_object_new_checked:
5148 * @klass: the class of the object that we want to create
5149 * @error: set on error
5151 * Returns: a newly created object whose definition is
5152 * looked up using @klass. This will not invoke any constructors,
5153 * so the consumer of this routine has to invoke any constructors on
5154 * its own to initialize the object.
5156 * It returns NULL on failure and sets @error.
5159 mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
5161 MONO_REQ_GC_UNSAFE_MODE;
5165 vtable = mono_class_vtable (domain, klass);
5166 g_assert (vtable); /* FIXME don't swallow the error */
5168 MonoObject *o = mono_object_new_specific_checked (vtable, error);
5173 * mono_object_new_pinned:
5175 * Same as mono_object_new, but the returned object will be pinned.
5176 * For SGEN, these objects will only be freed at appdomain unload.
5179 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
5181 MONO_REQ_GC_UNSAFE_MODE;
5185 mono_error_init (error);
5187 vtable = mono_class_vtable (domain, klass);
5188 g_assert (vtable); /* FIXME don't swallow the error */
5190 MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
5192 if (G_UNLIKELY (!o))
5193 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
5194 else if (G_UNLIKELY (vtable->klass->has_finalize))
5195 mono_object_register_finalizer (o);
5201 * mono_object_new_specific:
5202 * @vtable: the vtable of the object that we want to create
5204 * Returns: A newly created object with class and domain specified
5208 mono_object_new_specific (MonoVTable *vtable)
5211 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5212 mono_error_cleanup (&error);
5218 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
5220 MONO_REQ_GC_UNSAFE_MODE;
5224 mono_error_init (error);
5226 /* check for is_com_object for COM Interop */
5227 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
5230 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
5233 MonoClass *klass = mono_class_get_activation_services_class ();
5236 mono_class_init (klass);
5238 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
5240 mono_error_set_not_supported (error, "Linked away.");
5243 vtable->domain->create_proxy_for_type_method = im;
5246 pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
5247 if (!mono_error_ok (error))
5250 o = mono_runtime_invoke_checked (im, NULL, pa, error);
5251 if (!mono_error_ok (error))
5258 return mono_object_new_alloc_specific_checked (vtable, error);
5262 ves_icall_object_new_specific (MonoVTable *vtable)
5265 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5266 mono_error_set_pending_exception (&error);
5272 * mono_object_new_alloc_specific:
5273 * @vtable: virtual table for the object.
5275 * This function allocates a new `MonoObject` with the type derived
5276 * from the @vtable information. If the class of this object has a
5277 * finalizer, then the object will be tracked for finalization.
5279 * This method might raise an exception on errors. Use the
5280 * `mono_object_new_fast_checked` method if you want to manually raise
5283 * Returns: the allocated object.
5286 mono_object_new_alloc_specific (MonoVTable *vtable)
5289 MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
5290 mono_error_cleanup (&error);
5296 * mono_object_new_alloc_specific_checked:
5297 * @vtable: virtual table for the object.
5298 * @error: holds the error return value.
5300 * This function allocates a new `MonoObject` with the type derived
5301 * from the @vtable information. If the class of this object has a
5302 * finalizer, then the object will be tracked for finalization.
5304 * If there is not enough memory, the @error parameter will be set
5305 * and will contain a user-visible message with the amount of bytes
5306 * that were requested.
5308 * Returns: the allocated object, or NULL if there is not enough memory
5312 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
5314 MONO_REQ_GC_UNSAFE_MODE;
5318 mono_error_init (error);
5320 o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5322 if (G_UNLIKELY (!o))
5323 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5324 else if (G_UNLIKELY (vtable->klass->has_finalize))
5325 mono_object_register_finalizer (o);
5331 * mono_object_new_fast:
5332 * @vtable: virtual table for the object.
5334 * This function allocates a new `MonoObject` with the type derived
5335 * from the @vtable information. The returned object is not tracked
5336 * for finalization. If your object implements a finalizer, you should
5337 * use `mono_object_new_alloc_specific` instead.
5339 * This method might raise an exception on errors. Use the
5340 * `mono_object_new_fast_checked` method if you want to manually raise
5343 * Returns: the allocated object.
5346 mono_object_new_fast (MonoVTable *vtable)
5349 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5350 mono_error_cleanup (&error);
5356 * mono_object_new_fast_checked:
5357 * @vtable: virtual table for the object.
5358 * @error: holds the error return value.
5360 * This function allocates a new `MonoObject` with the type derived
5361 * from the @vtable information. The returned object is not tracked
5362 * for finalization. If your object implements a finalizer, you should
5363 * use `mono_object_new_alloc_specific_checked` instead.
5365 * If there is not enough memory, the @error parameter will be set
5366 * and will contain a user-visible message with the amount of bytes
5367 * that were requested.
5369 * Returns: the allocated object, or NULL if there is not enough memory
5373 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
5375 MONO_REQ_GC_UNSAFE_MODE;
5379 mono_error_init (error);
5381 o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5383 if (G_UNLIKELY (!o))
5384 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5390 ves_icall_object_new_fast (MonoVTable *vtable)
5393 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5394 mono_error_set_pending_exception (&error);
5400 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
5402 MONO_REQ_GC_UNSAFE_MODE;
5406 mono_error_init (error);
5408 o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
5410 if (G_UNLIKELY (!o))
5411 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5412 else if (G_UNLIKELY (vtable->klass->has_finalize))
5413 mono_object_register_finalizer (o);
5419 * mono_class_get_allocation_ftn:
5421 * @for_box: the object will be used for boxing
5422 * @pass_size_in_words:
5424 * Return the allocation function appropriate for the given class.
5428 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
5430 MONO_REQ_GC_NEUTRAL_MODE;
5432 *pass_size_in_words = FALSE;
5434 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass) || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
5435 return ves_icall_object_new_specific;
5437 if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
5439 return ves_icall_object_new_fast;
5442 * FIXME: This is actually slower than ves_icall_object_new_fast, because
5443 * of the overhead of parameter passing.
5446 *pass_size_in_words = TRUE;
5447 #ifdef GC_REDIRECT_TO_LOCAL
5448 return GC_local_gcj_fast_malloc;
5450 return GC_gcj_fast_malloc;
5455 return ves_icall_object_new_specific;
5459 * mono_object_new_from_token:
5460 * @image: Context where the type_token is hosted
5461 * @token: a token of the type that we want to create
5463 * Returns: A newly created object whose definition is
5464 * looked up using @token in the @image image
5467 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
5469 MONO_REQ_GC_UNSAFE_MODE;
5475 klass = mono_class_get_checked (image, token, &error);
5476 mono_error_assert_ok (&error);
5478 result = mono_object_new_checked (domain, klass, &error);
5480 mono_error_cleanup (&error);
5487 * mono_object_clone:
5488 * @obj: the object to clone
5490 * Returns: A newly created object who is a shallow copy of @obj
5493 mono_object_clone (MonoObject *obj)
5496 MonoObject *o = mono_object_clone_checked (obj, &error);
5497 mono_error_cleanup (&error);
5503 mono_object_clone_checked (MonoObject *obj, MonoError *error)
5505 MONO_REQ_GC_UNSAFE_MODE;
5510 mono_error_init (error);
5512 size = obj->vtable->klass->instance_size;
5514 if (obj->vtable->klass->rank)
5515 return (MonoObject*)mono_array_clone_checked ((MonoArray*)obj, error);
5517 o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
5519 if (G_UNLIKELY (!o)) {
5520 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5524 /* If the object doesn't contain references this will do a simple memmove. */
5525 mono_gc_wbarrier_object_copy (o, obj);
5527 if (obj->vtable->klass->has_finalize)
5528 mono_object_register_finalizer (o);
5533 * mono_array_full_copy:
5534 * @src: source array to copy
5535 * @dest: destination array
5537 * Copies the content of one array to another with exactly the same type and size.
5540 mono_array_full_copy (MonoArray *src, MonoArray *dest)
5542 MONO_REQ_GC_UNSAFE_MODE;
5545 MonoClass *klass = src->obj.vtable->klass;
5547 g_assert (klass == dest->obj.vtable->klass);
5549 size = mono_array_length (src);
5550 g_assert (size == mono_array_length (dest));
5551 size *= mono_array_element_size (klass);
5553 if (klass->element_class->valuetype) {
5554 if (klass->element_class->has_references)
5555 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
5557 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5559 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
5562 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5567 * mono_array_clone_in_domain:
5568 * @domain: the domain in which the array will be cloned into
5569 * @array: the array to clone
5570 * @error: set on error
5572 * This routine returns a copy of the array that is hosted on the
5573 * specified MonoDomain. On failure returns NULL and sets @error.
5576 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array, MonoError *error)
5578 MONO_REQ_GC_UNSAFE_MODE;
5583 MonoClass *klass = array->obj.vtable->klass;
5585 mono_error_init (error);
5587 if (array->bounds == NULL) {
5588 size = mono_array_length (array);
5589 o = mono_array_new_full_checked (domain, klass, &size, NULL, error);
5590 return_val_if_nok (error, NULL);
5592 size *= mono_array_element_size (klass);
5594 if (klass->element_class->valuetype) {
5595 if (klass->element_class->has_references)
5596 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5598 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5600 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5603 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5608 sizes = (uintptr_t *)alloca (klass->rank * sizeof(intptr_t) * 2);
5609 size = mono_array_element_size (klass);
5610 for (i = 0; i < klass->rank; ++i) {
5611 sizes [i] = array->bounds [i].length;
5612 size *= array->bounds [i].length;
5613 sizes [i + klass->rank] = array->bounds [i].lower_bound;
5615 o = mono_array_new_full_checked (domain, klass, sizes, (intptr_t*)sizes + klass->rank, error);
5616 return_val_if_nok (error, NULL);
5618 if (klass->element_class->valuetype) {
5619 if (klass->element_class->has_references)
5620 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5622 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5624 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5627 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5635 * @array: the array to clone
5637 * Returns: A newly created array who is a shallow copy of @array
5640 mono_array_clone (MonoArray *array)
5642 MONO_REQ_GC_UNSAFE_MODE;
5645 MonoArray *result = mono_array_clone_checked (array, &error);
5646 mono_error_cleanup (&error);
5651 * mono_array_clone_checked:
5652 * @array: the array to clone
5653 * @error: set on error
5655 * Returns: A newly created array who is a shallow copy of @array. On
5656 * failure returns NULL and sets @error.
5659 mono_array_clone_checked (MonoArray *array, MonoError *error)
5662 MONO_REQ_GC_UNSAFE_MODE;
5663 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array, error);
5666 /* helper macros to check for overflow when calculating the size of arrays */
5667 #ifdef MONO_BIG_ARRAYS
5668 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
5669 #define MYGUINT_MAX MYGUINT64_MAX
5670 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5671 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
5672 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5673 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
5674 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
5676 #define MYGUINT32_MAX 4294967295U
5677 #define MYGUINT_MAX MYGUINT32_MAX
5678 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5679 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
5680 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5681 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
5682 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
5686 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
5688 MONO_REQ_GC_NEUTRAL_MODE;
5692 byte_len = mono_array_element_size (klass);
5693 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
5696 if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
5698 byte_len += MONO_SIZEOF_MONO_ARRAY;
5706 * mono_array_new_full:
5707 * @domain: domain where the object is created
5708 * @array_class: array class
5709 * @lengths: lengths for each dimension in the array
5710 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
5712 * This routine creates a new array objects with the given dimensions,
5713 * lower bounds and type.
5716 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
5719 MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
5720 mono_error_cleanup (&error);
5726 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
5728 MONO_REQ_GC_UNSAFE_MODE;
5730 uintptr_t byte_len = 0, len, bounds_size;
5733 MonoArrayBounds *bounds;
5737 mono_error_init (error);
5739 if (!array_class->inited)
5740 mono_class_init (array_class);
5744 /* A single dimensional array with a 0 lower bound is the same as an szarray */
5745 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
5747 if (len > MONO_ARRAY_MAX_INDEX) {
5748 mono_error_set_generic_error (error, "System", "OverflowException", "");
5753 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
5755 for (i = 0; i < array_class->rank; ++i) {
5756 if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
5757 mono_error_set_generic_error (error, "System", "OverflowException", "");
5760 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5761 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5768 if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5769 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5775 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5776 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5779 byte_len = (byte_len + 3) & ~3;
5780 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5781 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5784 byte_len += bounds_size;
5787 * Following three lines almost taken from mono_object_new ():
5788 * they need to be kept in sync.
5790 vtable = mono_class_vtable_full (domain, array_class, error);
5791 return_val_if_nok (error, NULL);
5794 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5796 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5798 if (G_UNLIKELY (!o)) {
5799 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", byte_len);
5803 array = (MonoArray*)o;
5805 bounds = array->bounds;
5808 for (i = 0; i < array_class->rank; ++i) {
5809 bounds [i].length = lengths [i];
5811 bounds [i].lower_bound = lower_bounds [i];
5820 * @domain: domain where the object is created
5821 * @eclass: element class
5822 * @n: number of array elements
5824 * This routine creates a new szarray with @n elements of type @eclass.
5827 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5829 MONO_REQ_GC_UNSAFE_MODE;
5832 MonoArray *result = mono_array_new_checked (domain, eclass, n, &error);
5833 mono_error_cleanup (&error);
5838 * mono_array_new_checked:
5839 * @domain: domain where the object is created
5840 * @eclass: element class
5841 * @n: number of array elements
5842 * @error: set on error
5844 * This routine creates a new szarray with @n elements of type @eclass.
5845 * On failure returns NULL and sets @error.
5848 mono_array_new_checked (MonoDomain *domain, MonoClass *eclass, uintptr_t n, MonoError *error)
5852 mono_error_init (error);
5854 ac = mono_array_class_get (eclass, 1);
5857 MonoVTable *vtable = mono_class_vtable_full (domain, ac, error);
5858 return_val_if_nok (error, NULL);
5860 return mono_array_new_specific_checked (vtable, n, error);
5864 ves_icall_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5867 MonoArray *arr = mono_array_new_checked (domain, eclass, n, &error);
5868 mono_error_set_pending_exception (&error);
5874 * mono_array_new_specific:
5875 * @vtable: a vtable in the appropriate domain for an initialized class
5876 * @n: number of array elements
5878 * This routine is a fast alternative to mono_array_new() for code which
5879 * can be sure about the domain it operates in.
5882 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5885 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5886 mono_error_cleanup (&error);
5892 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
5894 MONO_REQ_GC_UNSAFE_MODE;
5899 mono_error_init (error);
5901 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
5902 mono_error_set_generic_error (error, "System", "OverflowException", "");
5906 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
5907 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5910 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
5912 if (G_UNLIKELY (!o)) {
5913 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", byte_len);
5917 return (MonoArray*)o;
5921 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
5924 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5925 mono_error_set_pending_exception (&error);
5931 * mono_string_new_utf16:
5932 * @text: a pointer to an utf16 string
5933 * @len: the length of the string
5935 * Returns: A newly created string object which contains @text.
5938 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
5940 MONO_REQ_GC_UNSAFE_MODE;
5943 MonoString *res = NULL;
5944 res = mono_string_new_utf16_checked (domain, text, len, &error);
5945 mono_error_cleanup (&error);
5951 * mono_string_new_utf16_checked:
5952 * @text: a pointer to an utf16 string
5953 * @len: the length of the string
5954 * @error: written on error.
5956 * Returns: A newly created string object which contains @text.
5957 * On error, returns NULL and sets @error.
5960 mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
5962 MONO_REQ_GC_UNSAFE_MODE;
5966 mono_error_init (error);
5968 s = mono_string_new_size_checked (domain, len, error);
5970 memcpy (mono_string_chars (s), text, len * 2);
5976 * mono_string_new_utf32:
5977 * @text: a pointer to an utf32 string
5978 * @len: the length of the string
5979 * @error: set on failure.
5981 * Returns: A newly created string object which contains @text. On failure returns NULL and sets @error.
5984 mono_string_new_utf32_checked (MonoDomain *domain, const mono_unichar4 *text, gint32 len, MonoError *error)
5986 MONO_REQ_GC_UNSAFE_MODE;
5989 mono_unichar2 *utf16_output = NULL;
5990 gint32 utf16_len = 0;
5991 GError *gerror = NULL;
5992 glong items_written;
5994 mono_error_init (error);
5995 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
5998 g_error_free (gerror);
6000 while (utf16_output [utf16_len]) utf16_len++;
6002 s = mono_string_new_size_checked (domain, utf16_len, error);
6003 return_val_if_nok (error, NULL);
6005 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
6007 g_free (utf16_output);
6013 * mono_string_new_utf32:
6014 * @text: a pointer to an utf32 string
6015 * @len: the length of the string
6017 * Returns: A newly created string object which contains @text.
6020 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
6023 MonoString *result = mono_string_new_utf32_checked (domain, text, len, &error);
6024 mono_error_cleanup (&error);
6029 * mono_string_new_size:
6030 * @text: a pointer to an utf16 string
6031 * @len: the length of the string
6033 * Returns: A newly created string object of @len
6036 mono_string_new_size (MonoDomain *domain, gint32 len)
6039 MonoString *str = mono_string_new_size_checked (domain, len, &error);
6040 mono_error_cleanup (&error);
6046 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
6048 MONO_REQ_GC_UNSAFE_MODE;
6054 mono_error_init (error);
6056 /* check for overflow */
6057 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
6058 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
6062 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
6063 g_assert (size > 0);
6065 vtable = mono_class_vtable (domain, mono_defaults.string_class);
6068 s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
6070 if (G_UNLIKELY (!s)) {
6071 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6079 * mono_string_new_len:
6080 * @text: a pointer to an utf8 string
6081 * @length: number of bytes in @text to consider
6083 * Returns: A newly created string object which contains @text.
6086 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
6088 MONO_REQ_GC_UNSAFE_MODE;
6091 MonoString *result = mono_string_new_len_checked (domain, text, length, &error);
6092 mono_error_cleanup (&error);
6097 * mono_string_new_len_checked:
6098 * @text: a pointer to an utf8 string
6099 * @length: number of bytes in @text to consider
6100 * @error: set on error
6102 * Returns: A newly created string object which contains @text. On
6103 * failure returns NULL and sets @error.
6106 mono_string_new_len_checked (MonoDomain *domain, const char *text, guint length, MonoError *error)
6108 MONO_REQ_GC_UNSAFE_MODE;
6110 mono_error_init (error);
6112 GError *eg_error = NULL;
6113 MonoString *o = NULL;
6115 glong items_written;
6117 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
6120 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6122 g_error_free (eg_error);
6131 * @text: a pointer to an utf8 string
6133 * Returns: A newly created string object which contains @text.
6135 * This function asserts if it cannot allocate a new string.
6137 * @deprecated Use mono_string_new_checked in new code.
6140 mono_string_new (MonoDomain *domain, const char *text)
6143 MonoString *res = NULL;
6144 res = mono_string_new_checked (domain, text, &error);
6145 mono_error_assert_ok (&error);
6150 * mono_string_new_checked:
6151 * @text: a pointer to an utf8 string
6152 * @merror: set on error
6154 * Returns: A newly created string object which contains @text.
6155 * On error returns NULL and sets @merror.
6158 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
6160 MONO_REQ_GC_UNSAFE_MODE;
6162 GError *eg_error = NULL;
6163 MonoString *o = NULL;
6165 glong items_written;
6168 mono_error_init (error);
6172 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &eg_error);
6175 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6177 g_error_free (eg_error);
6181 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
6186 MonoString *o = NULL;
6188 if (!g_utf8_validate (text, -1, &end)) {
6189 mono_error_set_argument (error, "text", "Not a valid utf8 string");
6193 len = g_utf8_strlen (text, -1);
6194 o = mono_string_new_size_checked (domain, len, error);
6197 str = mono_string_chars (o);
6199 while (text < end) {
6200 *str++ = g_utf8_get_char (text);
6201 text = g_utf8_next_char (text);
6210 * mono_string_new_wrapper:
6211 * @text: pointer to utf8 characters.
6213 * Helper function to create a string object from @text in the current domain.
6216 mono_string_new_wrapper (const char *text)
6218 MONO_REQ_GC_UNSAFE_MODE;
6220 MonoDomain *domain = mono_domain_get ();
6223 return mono_string_new (domain, text);
6230 * @class: the class of the value
6231 * @value: a pointer to the unboxed data
6233 * Returns: A newly created object which contains @value.
6236 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
6239 MonoObject *result = mono_value_box_checked (domain, klass, value, &error);
6240 mono_error_cleanup (&error);
6245 * mono_value_box_checked:
6246 * @domain: the domain of the new object
6247 * @class: the class of the value
6248 * @value: a pointer to the unboxed data
6249 * @error: set on error
6251 * Returns: A newly created object which contains @value. On failure
6252 * returns NULL and sets @error.
6255 mono_value_box_checked (MonoDomain *domain, MonoClass *klass, gpointer value, MonoError *error)
6257 MONO_REQ_GC_UNSAFE_MODE;
6262 mono_error_init (error);
6264 g_assert (klass->valuetype);
6265 if (mono_class_is_nullable (klass))
6266 return mono_nullable_box ((guint8 *)value, klass, error);
6268 vtable = mono_class_vtable (domain, klass);
6271 size = mono_class_instance_size (klass);
6272 res = mono_object_new_alloc_specific_checked (vtable, error);
6273 return_val_if_nok (error, NULL);
6275 size = size - sizeof (MonoObject);
6278 g_assert (size == mono_class_value_size (klass, NULL));
6279 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
6281 #if NO_UNALIGNED_ACCESS
6282 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6286 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
6289 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
6292 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
6295 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
6298 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6302 if (klass->has_finalize) {
6303 mono_object_register_finalizer (res);
6304 return_val_if_nok (error, NULL);
6311 * @dest: destination pointer
6312 * @src: source pointer
6313 * @klass: a valuetype class
6315 * Copy a valuetype from @src to @dest. This function must be used
6316 * when @klass contains references fields.
6319 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
6321 MONO_REQ_GC_UNSAFE_MODE;
6323 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
6327 * mono_value_copy_array:
6328 * @dest: destination array
6329 * @dest_idx: index in the @dest array
6330 * @src: source pointer
6331 * @count: number of items
6333 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
6334 * This function must be used when @klass contains references fields.
6335 * Overlap is handled.
6338 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
6340 MONO_REQ_GC_UNSAFE_MODE;
6342 int size = mono_array_element_size (dest->obj.vtable->klass);
6343 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
6344 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
6345 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
6349 * mono_object_get_domain:
6350 * @obj: object to query
6352 * Returns: the MonoDomain where the object is hosted
6355 mono_object_get_domain (MonoObject *obj)
6357 MONO_REQ_GC_UNSAFE_MODE;
6359 return mono_object_domain (obj);
6363 * mono_object_get_class:
6364 * @obj: object to query
6366 * Use this function to obtain the `MonoClass*` for a given `MonoObject`.
6368 * Returns: the MonoClass of the object.
6371 mono_object_get_class (MonoObject *obj)
6373 MONO_REQ_GC_UNSAFE_MODE;
6375 return mono_object_class (obj);
6378 * mono_object_get_size:
6379 * @o: object to query
6381 * Returns: the size, in bytes, of @o
6384 mono_object_get_size (MonoObject* o)
6386 MONO_REQ_GC_UNSAFE_MODE;
6388 MonoClass* klass = mono_object_class (o);
6389 if (klass == mono_defaults.string_class) {
6390 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
6391 } else if (o->vtable->rank) {
6392 MonoArray *array = (MonoArray*)o;
6393 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
6394 if (array->bounds) {
6397 size += sizeof (MonoArrayBounds) * o->vtable->rank;
6401 return mono_class_instance_size (klass);
6406 * mono_object_unbox:
6407 * @obj: object to unbox
6409 * Returns: a pointer to the start of the valuetype boxed in this
6412 * This method will assert if the object passed is not a valuetype.
6415 mono_object_unbox (MonoObject *obj)
6417 MONO_REQ_GC_UNSAFE_MODE;
6419 /* add assert for valuetypes? */
6420 g_assert (obj->vtable->klass->valuetype);
6421 return ((char*)obj) + sizeof (MonoObject);
6425 * mono_object_isinst:
6427 * @klass: a pointer to a class
6429 * Returns: @obj if @obj is derived from @klass or NULL otherwise.
6432 mono_object_isinst (MonoObject *obj, MonoClass *klass)
6434 MONO_REQ_GC_UNSAFE_MODE;
6437 MonoObject *result = mono_object_isinst_checked (obj, klass, &error);
6438 mono_error_cleanup (&error);
6444 * mono_object_isinst_checked:
6446 * @klass: a pointer to a class
6447 * @error: set on error
6449 * Returns: @obj if @obj is derived from @klass or NULL if it isn't.
6450 * On failure returns NULL and sets @error.
6453 mono_object_isinst_checked (MonoObject *obj, MonoClass *klass, MonoError *error)
6455 MONO_REQ_GC_UNSAFE_MODE;
6457 mono_error_init (error);
6459 MonoObject *result = NULL;
6462 mono_class_init (klass);
6464 if (mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
6465 result = mono_object_isinst_mbyref_checked (obj, klass, error);
6472 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
6476 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
6478 MONO_REQ_GC_UNSAFE_MODE;
6481 MonoObject *result = mono_object_isinst_mbyref_checked (obj, klass, &error);
6482 mono_error_cleanup (&error); /* FIXME better API that doesn't swallow the error */
6487 mono_object_isinst_mbyref_checked (MonoObject *obj, MonoClass *klass, MonoError *error)
6489 MONO_REQ_GC_UNSAFE_MODE;
6493 mono_error_init (error);
6500 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
6501 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
6505 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
6506 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
6509 MonoClass *oklass = vt->klass;
6510 if (mono_class_is_transparent_proxy (oklass))
6511 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
6513 mono_class_setup_supertypes (klass);
6514 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
6517 #ifndef DISABLE_REMOTING
6518 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
6520 MonoDomain *domain = mono_domain_get ();
6522 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
6523 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
6524 MonoMethod *im = NULL;
6527 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
6529 mono_error_set_not_supported (error, "Linked away.");
6532 im = mono_object_get_virtual_method (rp, im);
6535 pa [0] = mono_type_get_object_checked (domain, &klass->byval_arg, error);
6536 return_val_if_nok (error, NULL);
6539 res = mono_runtime_invoke_checked (im, rp, pa, error);
6540 return_val_if_nok (error, NULL);
6542 if (*(MonoBoolean *) mono_object_unbox(res)) {
6543 /* Update the vtable of the remote type, so it can safely cast to this new type */
6544 mono_upgrade_remote_class (domain, obj, klass, error);
6545 return_val_if_nok (error, NULL);
6549 #endif /* DISABLE_REMOTING */
6554 * mono_object_castclass_mbyref:
6556 * @klass: a pointer to a class
6558 * Returns: @obj if @obj is derived from @klass, returns NULL otherwise.
6561 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
6563 MONO_REQ_GC_UNSAFE_MODE;
6566 if (!obj) return NULL;
6567 if (mono_object_isinst_mbyref_checked (obj, klass, &error)) return obj;
6568 mono_error_cleanup (&error);
6573 MonoDomain *orig_domain;
6579 str_lookup (MonoDomain *domain, gpointer user_data)
6581 MONO_REQ_GC_UNSAFE_MODE;
6583 LDStrInfo *info = (LDStrInfo *)user_data;
6584 if (info->res || domain == info->orig_domain)
6586 info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
6590 mono_string_get_pinned (MonoString *str, MonoError *error)
6592 MONO_REQ_GC_UNSAFE_MODE;
6594 mono_error_init (error);
6596 /* We only need to make a pinned version of a string if this is a moving GC */
6597 if (!mono_gc_is_moving ())
6601 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
6602 news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
6604 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
6605 news->length = mono_string_length (str);
6607 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6613 mono_string_is_interned_lookup (MonoString *str, int insert, MonoError *error)
6615 MONO_REQ_GC_UNSAFE_MODE;
6617 MonoGHashTable *ldstr_table;
6618 MonoString *s, *res;
6621 mono_error_init (error);
6623 domain = ((MonoObject *)str)->vtable->domain;
6624 ldstr_table = domain->ldstr_table;
6626 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6632 /* Allocate outside the lock */
6634 s = mono_string_get_pinned (str, error);
6635 return_val_if_nok (error, NULL);
6638 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6643 mono_g_hash_table_insert (ldstr_table, s, s);
6648 LDStrInfo ldstr_info;
6649 ldstr_info.orig_domain = domain;
6650 ldstr_info.ins = str;
6651 ldstr_info.res = NULL;
6653 mono_domain_foreach (str_lookup, &ldstr_info);
6654 if (ldstr_info.res) {
6656 * the string was already interned in some other domain:
6657 * intern it in the current one as well.
6659 mono_g_hash_table_insert (ldstr_table, str, str);
6669 * mono_string_is_interned:
6670 * @o: String to probe
6672 * Returns whether the string has been interned.
6675 mono_string_is_interned (MonoString *o)
6678 MonoString *result = mono_string_is_interned_lookup (o, FALSE, &error);
6679 /* This function does not fail. */
6680 mono_error_assert_ok (&error);
6685 * mono_string_intern:
6686 * @o: String to intern
6688 * Interns the string passed.
6689 * Returns: The interned string.
6692 mono_string_intern (MonoString *str)
6695 MonoString *result = mono_string_intern_checked (str, &error);
6696 mono_error_assert_ok (&error);
6701 * mono_string_intern_checked:
6702 * @o: String to intern
6703 * @error: set on error.
6705 * Interns the string passed.
6706 * Returns: The interned string. On failure returns NULL and sets @error
6709 mono_string_intern_checked (MonoString *str, MonoError *error)
6711 MONO_REQ_GC_UNSAFE_MODE;
6713 mono_error_init (error);
6715 return mono_string_is_interned_lookup (str, TRUE, error);
6720 * @domain: the domain where the string will be used.
6721 * @image: a metadata context
6722 * @idx: index into the user string table.
6724 * Implementation for the ldstr opcode.
6725 * Returns: a loaded string from the @image/@idx combination.
6728 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
6731 MonoString *result = mono_ldstr_checked (domain, image, idx, &error);
6732 mono_error_cleanup (&error);
6737 * mono_ldstr_checked:
6738 * @domain: the domain where the string will be used.
6739 * @image: a metadata context
6740 * @idx: index into the user string table.
6741 * @error: set on error.
6743 * Implementation for the ldstr opcode.
6744 * Returns: a loaded string from the @image/@idx combination.
6745 * On failure returns NULL and sets @error.
6748 mono_ldstr_checked (MonoDomain *domain, MonoImage *image, guint32 idx, MonoError *error)
6750 MONO_REQ_GC_UNSAFE_MODE;
6751 mono_error_init (error);
6753 if (image->dynamic) {
6754 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL, error);
6757 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6758 return NULL; /*FIXME we should probably be raising an exception here*/
6759 MonoString *str = mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx), error);
6765 * mono_ldstr_metadata_sig
6766 * @domain: the domain for the string
6767 * @sig: the signature of a metadata string
6768 * @error: set on error
6770 * Returns: a MonoString for a string stored in the metadata. On
6771 * failure returns NULL and sets @error.
6774 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error)
6776 MONO_REQ_GC_UNSAFE_MODE;
6778 mono_error_init (error);
6779 const char *str = sig;
6780 MonoString *o, *interned;
6783 len2 = mono_metadata_decode_blob_size (str, &str);
6786 o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, error);
6787 return_val_if_nok (error, NULL);
6788 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
6791 guint16 *p2 = (guint16*)mono_string_chars (o);
6792 for (i = 0; i < len2; ++i) {
6793 *p2 = GUINT16_FROM_LE (*p2);
6799 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6802 return interned; /* o will get garbage collected */
6804 o = mono_string_get_pinned (o, error);
6807 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6809 mono_g_hash_table_insert (domain->ldstr_table, o, o);
6819 * mono_string_to_utf8:
6820 * @s: a System.String
6822 * Returns the UTF8 representation for @s.
6823 * The resulting buffer needs to be freed with mono_free().
6825 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
6828 mono_string_to_utf8 (MonoString *s)
6830 MONO_REQ_GC_UNSAFE_MODE;
6833 char *result = mono_string_to_utf8_checked (s, &error);
6835 if (!mono_error_ok (&error))
6836 mono_error_raise_exception (&error);
6841 * mono_string_to_utf8_checked:
6842 * @s: a System.String
6843 * @error: a MonoError.
6845 * Converts a MonoString to its UTF8 representation. May fail; check
6846 * @error to determine whether the conversion was successful.
6847 * The resulting buffer should be freed with mono_free().
6850 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
6852 MONO_REQ_GC_UNSAFE_MODE;
6856 GError *gerror = NULL;
6858 mono_error_init (error);
6864 return g_strdup ("");
6866 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
6868 mono_error_set_argument (error, "string", "%s", gerror->message);
6869 g_error_free (gerror);
6872 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6873 if (s->length > written) {
6874 /* allocate the total length and copy the part of the string that has been converted */
6875 char *as2 = (char *)g_malloc0 (s->length);
6876 memcpy (as2, as, written);
6885 * mono_string_to_utf8_ignore:
6888 * Converts a MonoString to its UTF8 representation. Will ignore
6889 * invalid surrogate pairs.
6890 * The resulting buffer should be freed with mono_free().
6894 mono_string_to_utf8_ignore (MonoString *s)
6896 MONO_REQ_GC_UNSAFE_MODE;
6905 return g_strdup ("");
6907 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
6909 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6910 if (s->length > written) {
6911 /* allocate the total length and copy the part of the string that has been converted */
6912 char *as2 = (char *)g_malloc0 (s->length);
6913 memcpy (as2, as, written);
6922 * mono_string_to_utf8_image_ignore:
6923 * @s: a System.String
6925 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
6928 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
6930 MONO_REQ_GC_UNSAFE_MODE;
6932 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
6936 * mono_string_to_utf8_mp_ignore:
6937 * @s: a System.String
6939 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
6942 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
6944 MONO_REQ_GC_UNSAFE_MODE;
6946 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
6951 * mono_string_to_utf16:
6954 * Return an null-terminated array of the utf-16 chars
6955 * contained in @s. The result must be freed with g_free().
6956 * This is a temporary helper until our string implementation
6957 * is reworked to always include the null terminating char.
6960 mono_string_to_utf16 (MonoString *s)
6962 MONO_REQ_GC_UNSAFE_MODE;
6969 as = (char *)g_malloc ((s->length * 2) + 2);
6970 as [(s->length * 2)] = '\0';
6971 as [(s->length * 2) + 1] = '\0';
6974 return (gunichar2 *)(as);
6977 memcpy (as, mono_string_chars(s), s->length * 2);
6978 return (gunichar2 *)(as);
6982 * mono_string_to_utf32:
6985 * Return an null-terminated array of the UTF-32 (UCS-4) chars
6986 * contained in @s. The result must be freed with g_free().
6989 mono_string_to_utf32 (MonoString *s)
6991 MONO_REQ_GC_UNSAFE_MODE;
6993 mono_unichar4 *utf32_output = NULL;
6994 GError *error = NULL;
6995 glong items_written;
7000 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
7003 g_error_free (error);
7005 return utf32_output;
7009 * mono_string_from_utf16:
7010 * @data: the UTF16 string (LPWSTR) to convert
7012 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
7014 * Returns: a MonoString.
7017 mono_string_from_utf16 (gunichar2 *data)
7020 MonoString *result = mono_string_from_utf16_checked (data, &error);
7021 mono_error_cleanup (&error);
7026 * mono_string_from_utf16_checked:
7027 * @data: the UTF16 string (LPWSTR) to convert
7028 * @error: set on error
7030 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
7032 * Returns: a MonoString. On failure sets @error and returns NULL.
7035 mono_string_from_utf16_checked (gunichar2 *data, MonoError *error)
7038 MONO_REQ_GC_UNSAFE_MODE;
7040 mono_error_init (error);
7041 MonoDomain *domain = mono_domain_get ();
7047 while (data [len]) len++;
7049 return mono_string_new_utf16_checked (domain, data, len, error);
7053 * mono_string_from_utf32:
7054 * @data: the UTF32 string (LPWSTR) to convert
7056 * Converts a UTF32 (UCS-4)to a MonoString.
7058 * Returns: a MonoString.
7061 mono_string_from_utf32 (mono_unichar4 *data)
7064 MonoString *result = mono_string_from_utf32_checked (data, &error);
7065 mono_error_cleanup (&error);
7070 * mono_string_from_utf32_checked:
7071 * @data: the UTF32 string (LPWSTR) to convert
7072 * @error: set on error
7074 * Converts a UTF32 (UCS-4)to a MonoString.
7076 * Returns: a MonoString. On failure returns NULL and sets @error.
7079 mono_string_from_utf32_checked (mono_unichar4 *data, MonoError *error)
7081 MONO_REQ_GC_UNSAFE_MODE;
7083 mono_error_init (error);
7084 MonoString* result = NULL;
7085 mono_unichar2 *utf16_output = NULL;
7086 GError *gerror = NULL;
7087 glong items_written;
7093 while (data [len]) len++;
7095 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &gerror);
7098 g_error_free (gerror);
7100 result = mono_string_from_utf16_checked (utf16_output, error);
7101 g_free (utf16_output);
7106 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
7108 MONO_REQ_GC_UNSAFE_MODE;
7115 r = mono_string_to_utf8_ignore (s);
7117 r = mono_string_to_utf8_checked (s, error);
7118 if (!mono_error_ok (error))
7125 len = strlen (r) + 1;
7127 mp_s = (char *)mono_mempool_alloc (mp, len);
7129 mp_s = (char *)mono_image_alloc (image, len);
7131 memcpy (mp_s, r, len);
7139 * mono_string_to_utf8_image:
7140 * @s: a System.String
7142 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
7145 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
7147 MONO_REQ_GC_UNSAFE_MODE;
7149 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
7153 * mono_string_to_utf8_mp:
7154 * @s: a System.String
7156 * Same as mono_string_to_utf8, but allocate the string from a mempool.
7159 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
7161 MONO_REQ_GC_UNSAFE_MODE;
7163 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
7167 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
7170 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
7172 eh_callbacks = *cbs;
7175 MonoRuntimeExceptionHandlingCallbacks *
7176 mono_get_eh_callbacks (void)
7178 return &eh_callbacks;
7182 * mono_raise_exception:
7183 * @ex: exception object
7185 * Signal the runtime that the exception @ex has been raised in unmanaged code.
7188 mono_raise_exception (MonoException *ex)
7190 MONO_REQ_GC_UNSAFE_MODE;
7193 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
7194 * that will cause gcc to omit the function epilog, causing problems when
7195 * the JIT tries to walk the stack, since the return address on the stack
7196 * will point into the next function in the executable, not this one.
7198 eh_callbacks.mono_raise_exception (ex);
7202 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
7204 MONO_REQ_GC_UNSAFE_MODE;
7206 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
7210 * mono_wait_handle_new:
7211 * @domain: Domain where the object will be created
7212 * @handle: Handle for the wait handle
7213 * @error: set on error.
7215 * Returns: A new MonoWaitHandle created in the given domain for the
7216 * given handle. On failure returns NULL and sets @rror.
7219 mono_wait_handle_new (MonoDomain *domain, HANDLE handle, MonoError *error)
7221 MONO_REQ_GC_UNSAFE_MODE;
7223 MonoWaitHandle *res;
7224 gpointer params [1];
7225 static MonoMethod *handle_set;
7227 mono_error_init (error);
7228 res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, error);
7229 return_val_if_nok (error, NULL);
7231 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
7233 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
7235 params [0] = &handle;
7237 mono_runtime_invoke_checked (handle_set, res, params, error);
7242 mono_wait_handle_get_handle (MonoWaitHandle *handle)
7244 MONO_REQ_GC_UNSAFE_MODE;
7246 static MonoClassField *f_safe_handle = NULL;
7249 if (!f_safe_handle) {
7250 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safeWaitHandle");
7251 g_assert (f_safe_handle);
7254 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
7260 mono_runtime_capture_context (MonoDomain *domain, MonoError *error)
7262 MONO_REQ_GC_UNSAFE_MODE;
7264 RuntimeInvokeFunction runtime_invoke;
7266 mono_error_init (error);
7268 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
7269 MonoMethod *method = mono_get_context_capture_method ();
7270 MonoMethod *wrapper;
7273 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
7274 domain->capture_context_runtime_invoke = mono_compile_method_checked (wrapper, error);
7275 return_val_if_nok (error, NULL);
7276 domain->capture_context_method = mono_compile_method_checked (method, error);
7277 return_val_if_nok (error, NULL);
7280 runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
7282 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
7285 * mono_async_result_new:
7286 * @domain:domain where the object will be created.
7287 * @handle: wait handle.
7288 * @state: state to pass to AsyncResult
7289 * @data: C closure data.
7290 * @error: set on error.
7292 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
7293 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
7294 * On failure returns NULL and sets @error.
7298 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data, MonoError *error)
7300 MONO_REQ_GC_UNSAFE_MODE;
7302 mono_error_init (error);
7303 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, error);
7304 return_val_if_nok (error, NULL);
7305 MonoObject *context = mono_runtime_capture_context (domain, error);
7306 return_val_if_nok (error, NULL);
7307 /* we must capture the execution context from the original thread */
7309 MONO_OBJECT_SETREF (res, execution_context, context);
7310 /* note: result may be null if the flow is suppressed */
7313 res->data = (void **)data;
7314 MONO_OBJECT_SETREF (res, object_data, object_data);
7315 MONO_OBJECT_SETREF (res, async_state, state);
7316 MonoWaitHandle *wait_handle = mono_wait_handle_new (domain, handle, error);
7317 return_val_if_nok (error, NULL);
7319 MONO_OBJECT_SETREF (res, handle, (MonoObject *) wait_handle);
7321 res->sync_completed = FALSE;
7322 res->completed = FALSE;
7328 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
7330 MONO_REQ_GC_UNSAFE_MODE;
7337 g_assert (ares->async_delegate);
7339 ac = (MonoAsyncCall*) ares->object_data;
7341 res = mono_runtime_delegate_invoke_checked (ares->async_delegate, (void**) &ares->async_state, &error);
7342 if (mono_error_set_pending_exception (&error))
7345 gpointer wait_event = NULL;
7347 ac->msg->exc = NULL;
7348 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args, &error);
7349 if (mono_error_set_pending_exception (&error))
7351 MONO_OBJECT_SETREF (ac, res, res);
7353 mono_monitor_enter ((MonoObject*) ares);
7354 ares->completed = 1;
7356 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
7357 mono_monitor_exit ((MonoObject*) ares);
7359 if (wait_event != NULL)
7360 SetEvent (wait_event);
7362 if (ac->cb_method) {
7363 mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
7364 if (mono_error_set_pending_exception (&error))
7373 mono_message_init (MonoDomain *domain,
7374 MonoMethodMessage *this_obj,
7375 MonoReflectionMethod *method,
7376 MonoArray *out_args,
7379 MONO_REQ_GC_UNSAFE_MODE;
7381 static MonoClass *object_array_klass;
7382 static MonoClass *byte_array_klass;
7383 static MonoClass *string_array_klass;
7384 mono_error_init (error);
7385 MonoMethodSignature *sig = mono_method_signature (method->method);
7392 if (!object_array_klass) {
7395 klass = mono_array_class_get (mono_defaults.byte_class, 1);
7397 byte_array_klass = klass;
7399 klass = mono_array_class_get (mono_defaults.string_class, 1);
7401 string_array_klass = klass;
7403 klass = mono_array_class_get (mono_defaults.object_class, 1);
7406 mono_atomic_store_release (&object_array_klass, klass);
7409 MONO_OBJECT_SETREF (this_obj, method, method);
7411 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), sig->param_count, error);
7412 return_val_if_nok (error, FALSE);
7414 MONO_OBJECT_SETREF (this_obj, args, arr);
7416 arr = mono_array_new_specific_checked (mono_class_vtable (domain, byte_array_klass), sig->param_count, error);
7417 return_val_if_nok (error, FALSE);
7419 MONO_OBJECT_SETREF (this_obj, arg_types, arr);
7421 this_obj->async_result = NULL;
7422 this_obj->call_type = CallType_Sync;
7424 names = g_new (char *, sig->param_count);
7425 mono_method_get_param_names (method->method, (const char **) names);
7427 arr = mono_array_new_specific_checked (mono_class_vtable (domain, string_array_klass), sig->param_count, error);
7431 MONO_OBJECT_SETREF (this_obj, names, arr);
7433 for (i = 0; i < sig->param_count; i++) {
7434 name = mono_string_new_checked (domain, names [i], error);
7437 mono_array_setref (this_obj->names, i, name);
7441 for (i = 0, j = 0; i < sig->param_count; i++) {
7442 if (sig->params [i]->byref) {
7444 MonoObject* arg = (MonoObject *)mono_array_get (out_args, gpointer, j);
7445 mono_array_setref (this_obj->args, i, arg);
7449 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
7453 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
7456 mono_array_set (this_obj->arg_types, guint8, i, arg_type);
7465 #ifndef DISABLE_REMOTING
7467 * mono_remoting_invoke:
7468 * @real_proxy: pointer to a RealProxy object
7469 * @msg: The MonoMethodMessage to execute
7470 * @exc: used to store exceptions
7471 * @out_args: used to store output arguments
7473 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
7474 * IMessage interface and it is not trivial to extract results from there. So
7475 * we call an helper method PrivateInvoke instead of calling
7476 * RealProxy::Invoke() directly.
7478 * Returns: the result object.
7481 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, MonoObject **exc, MonoArray **out_args, MonoError *error)
7483 MONO_REQ_GC_UNSAFE_MODE;
7486 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
7491 mono_error_init (error);
7493 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
7496 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
7498 mono_error_set_not_supported (error, "Linked away.");
7501 real_proxy->vtable->domain->private_invoke_method = im;
7504 pa [0] = real_proxy;
7509 o = mono_runtime_try_invoke (im, NULL, pa, exc, error);
7510 return_val_if_nok (error, NULL);
7517 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
7518 MonoObject **exc, MonoArray **out_args, MonoError *error)
7520 MONO_REQ_GC_UNSAFE_MODE;
7522 static MonoClass *object_array_klass;
7523 mono_error_init (error);
7527 MonoMethodSignature *sig;
7529 int i, j, outarg_count = 0;
7531 #ifndef DISABLE_REMOTING
7532 if (target && mono_object_is_transparent_proxy (target)) {
7533 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
7534 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7535 target = tp->rp->unwrapped_server;
7537 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args, error);
7542 domain = mono_domain_get ();
7543 method = msg->method->method;
7544 sig = mono_method_signature (method);
7546 for (i = 0; i < sig->param_count; i++) {
7547 if (sig->params [i]->byref)
7551 if (!object_array_klass) {
7554 klass = mono_array_class_get (mono_defaults.object_class, 1);
7557 mono_memory_barrier ();
7558 object_array_klass = klass;
7561 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, error);
7562 return_val_if_nok (error, NULL);
7564 mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
7567 MonoObject *ret = mono_runtime_try_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc, error);
7568 return_val_if_nok (error, NULL);
7570 for (i = 0, j = 0; i < sig->param_count; i++) {
7571 if (sig->params [i]->byref) {
7573 arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
7574 mono_array_setref (*out_args, j, arg);
7583 * mono_object_to_string:
7585 * @exc: Any exception thrown by ToString (). May be NULL.
7587 * Returns: the result of calling ToString () on an object.
7590 mono_object_to_string (MonoObject *obj, MonoObject **exc)
7592 MONO_REQ_GC_UNSAFE_MODE;
7594 static MonoMethod *to_string = NULL;
7603 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
7605 method = mono_object_get_virtual_method (obj, to_string);
7607 // Unbox value type if needed
7608 if (mono_class_is_valuetype (mono_method_get_class (method))) {
7609 target = mono_object_unbox (obj);
7613 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
7614 if (*exc == NULL && !mono_error_ok (&error))
7615 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
7617 mono_error_cleanup (&error);
7619 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
7620 mono_error_raise_exception (&error); /* FIXME don't raise here */
7627 * mono_print_unhandled_exception:
7628 * @exc: The exception
7630 * Prints the unhandled exception.
7633 mono_print_unhandled_exception (MonoObject *exc)
7635 MONO_REQ_GC_UNSAFE_MODE;
7638 char *message = (char*)"";
7639 gboolean free_message = FALSE;
7642 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
7643 message = g_strdup ("OutOfMemoryException");
7644 free_message = TRUE;
7645 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
7646 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
7647 free_message = TRUE;
7650 if (((MonoException*)exc)->native_trace_ips) {
7651 message = mono_exception_get_native_backtrace ((MonoException*)exc);
7652 free_message = TRUE;
7654 MonoObject *other_exc = NULL;
7655 str = mono_object_to_string (exc, &other_exc);
7657 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
7658 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
7660 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
7661 original_backtrace, nested_backtrace);
7663 g_free (original_backtrace);
7664 g_free (nested_backtrace);
7665 free_message = TRUE;
7667 message = mono_string_to_utf8_checked (str, &error);
7668 if (!mono_error_ok (&error)) {
7669 mono_error_cleanup (&error);
7670 message = (char *) "";
7672 free_message = TRUE;
7679 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
7680 * exc->vtable->klass->name, message);
7682 g_printerr ("\nUnhandled Exception:\n%s\n", message);
7689 * mono_delegate_ctor_with_method:
7690 * @this: pointer to an uninitialized delegate object
7691 * @target: target object
7692 * @addr: pointer to native code
7694 * @error: set on error.
7696 * Initialize a delegate and sets a specific method, not the one
7697 * associated with addr. This is useful when sharing generic code.
7698 * In that case addr will most probably not be associated with the
7699 * correct instantiation of the method.
7700 * On failure returns FALSE and sets @error.
7703 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method, MonoError *error)
7705 MONO_REQ_GC_UNSAFE_MODE;
7707 mono_error_init (error);
7708 MonoDelegate *delegate = (MonoDelegate *)this_obj;
7710 g_assert (this_obj);
7713 g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
7716 delegate->method = method;
7718 mono_stats.delegate_creations++;
7720 #ifndef DISABLE_REMOTING
7721 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
7723 method = mono_marshal_get_remoting_invoke (method);
7724 delegate->method_ptr = mono_compile_method_checked (method, error);
7725 return_val_if_nok (error, FALSE);
7726 MONO_OBJECT_SETREF (delegate, target, target);
7730 delegate->method_ptr = addr;
7731 MONO_OBJECT_SETREF (delegate, target, target);
7734 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
7735 if (callbacks.init_delegate)
7736 callbacks.init_delegate (delegate);
7741 * mono_delegate_ctor:
7742 * @this: pointer to an uninitialized delegate object
7743 * @target: target object
7744 * @addr: pointer to native code
7745 * @error: set on error.
7747 * This is used to initialize a delegate.
7748 * On failure returns FALSE and sets @error.
7751 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoError *error)
7753 MONO_REQ_GC_UNSAFE_MODE;
7755 mono_error_init (error);
7756 MonoDomain *domain = mono_domain_get ();
7758 MonoMethod *method = NULL;
7762 ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
7764 if (!ji && domain != mono_get_root_domain ())
7765 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
7767 method = mono_jit_info_get_method (ji);
7768 g_assert (!method->klass->generic_container);
7771 return mono_delegate_ctor_with_method (this_obj, target, addr, method, error);
7775 * mono_method_call_message_new:
7776 * @method: method to encapsulate
7777 * @params: parameters to the method
7778 * @invoke: optional, delegate invoke.
7779 * @cb: async callback delegate.
7780 * @state: state passed to the async callback.
7781 * @error: set on error.
7783 * Translates arguments pointers into a MonoMethodMessage.
7784 * On failure returns NULL and sets @error.
7787 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
7788 MonoDelegate **cb, MonoObject **state, MonoError *error)
7790 MONO_REQ_GC_UNSAFE_MODE;
7792 mono_error_init (error);
7794 MonoDomain *domain = mono_domain_get ();
7795 MonoMethodSignature *sig = mono_method_signature (method);
7796 MonoMethodMessage *msg;
7799 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
7800 return_val_if_nok (error, NULL);
7803 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, error);
7804 return_val_if_nok (error, NULL);
7805 mono_message_init (domain, msg, rm, NULL, error);
7806 return_val_if_nok (error, NULL);
7807 count = sig->param_count - 2;
7809 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
7810 return_val_if_nok (error, NULL);
7811 mono_message_init (domain, msg, rm, NULL, error);
7812 return_val_if_nok (error, NULL);
7813 count = sig->param_count;
7816 for (i = 0; i < count; i++) {
7821 if (sig->params [i]->byref)
7822 vpos = *((gpointer *)params [i]);
7826 klass = mono_class_from_mono_type (sig->params [i]);
7828 if (klass->valuetype) {
7829 arg = mono_value_box_checked (domain, klass, vpos, error);
7830 return_val_if_nok (error, NULL);
7832 arg = *((MonoObject **)vpos);
7834 mono_array_setref (msg->args, i, arg);
7837 if (cb != NULL && state != NULL) {
7838 *cb = *((MonoDelegate **)params [i]);
7840 *state = *((MonoObject **)params [i]);
7847 * mono_method_return_message_restore:
7849 * Restore results from message based processing back to arguments pointers
7852 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args, MonoError *error)
7854 MONO_REQ_GC_UNSAFE_MODE;
7856 mono_error_init (error);
7858 MonoMethodSignature *sig = mono_method_signature (method);
7859 int i, j, type, size, out_len;
7861 if (out_args == NULL)
7863 out_len = mono_array_length (out_args);
7867 for (i = 0, j = 0; i < sig->param_count; i++) {
7868 MonoType *pt = sig->params [i];
7873 mono_error_set_execution_engine (error, "The proxy call returned an incorrect number of output arguments");
7877 arg = (char *)mono_array_get (out_args, gpointer, j);
7880 g_assert (type != MONO_TYPE_VOID);
7882 if (MONO_TYPE_IS_REFERENCE (pt)) {
7883 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
7886 MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
7887 size = mono_class_value_size (klass, NULL);
7888 if (klass->has_references)
7889 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
7891 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
7893 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
7894 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
7903 #ifndef DISABLE_REMOTING
7906 * mono_load_remote_field:
7907 * @this: pointer to an object
7908 * @klass: klass of the object containing @field
7909 * @field: the field to load
7910 * @res: a storage to store the result
7912 * This method is called by the runtime on attempts to load fields of
7913 * transparent proxy objects. @this points to such TP, @klass is the class of
7914 * the object containing @field. @res is a storage location which can be
7915 * used to store the result.
7917 * Returns: an address pointing to the value of field.
7920 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
7923 gpointer result = mono_load_remote_field_checked (this_obj, klass, field, res, &error);
7924 mono_error_cleanup (&error);
7929 * mono_load_remote_field_checked:
7930 * @this: pointer to an object
7931 * @klass: klass of the object containing @field
7932 * @field: the field to load
7933 * @res: a storage to store the result
7934 * @error: set on error
7936 * This method is called by the runtime on attempts to load fields of
7937 * transparent proxy objects. @this points to such TP, @klass is the class of
7938 * the object containing @field. @res is a storage location which can be
7939 * used to store the result.
7941 * Returns: an address pointing to the value of field. On failure returns NULL and sets @error.
7944 mono_load_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res, MonoError *error)
7946 MONO_REQ_GC_UNSAFE_MODE;
7948 static MonoMethod *getter = NULL;
7950 mono_error_init (error);
7952 MonoDomain *domain = mono_domain_get ();
7953 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7954 MonoClass *field_class;
7955 MonoMethodMessage *msg;
7956 MonoArray *out_args;
7960 g_assert (mono_object_is_transparent_proxy (this_obj));
7961 g_assert (res != NULL);
7963 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7964 mono_field_get_value (tp->rp->unwrapped_server, field, res);
7969 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
7971 mono_error_set_not_supported (error, "Linked away.");
7976 field_class = mono_class_from_mono_type (field->type);
7978 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
7979 return_val_if_nok (error, NULL);
7980 out_args = mono_array_new_checked (domain, mono_defaults.object_class, 1, error);
7981 return_val_if_nok (error, NULL);
7982 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, error);
7983 return_val_if_nok (error, NULL);
7984 mono_message_init (domain, msg, rm, out_args, error);
7985 return_val_if_nok (error, NULL);
7987 full_name = mono_type_get_full_name (klass);
7988 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7989 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7992 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
7993 return_val_if_nok (error, NULL);
7996 mono_error_set_exception_instance (error, (MonoException *)exc);
8000 if (mono_array_length (out_args) == 0)
8003 mono_gc_wbarrier_generic_store (res, mono_array_get (out_args, MonoObject *, 0));
8005 if (field_class->valuetype) {
8006 return ((char *)*res) + sizeof (MonoObject);
8012 * mono_load_remote_field_new:
8017 * Missing documentation.
8020 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
8024 MonoObject *result = mono_load_remote_field_new_checked (this_obj, klass, field, &error);
8025 mono_error_cleanup (&error);
8030 * mono_load_remote_field_new_icall:
8031 * @this: pointer to an object
8032 * @klass: klass of the object containing @field
8033 * @field: the field to load
8035 * This method is called by the runtime on attempts to load fields of
8036 * transparent proxy objects. @this points to such TP, @klass is the class of
8037 * the object containing @field.
8039 * Returns: a freshly allocated object containing the value of the
8040 * field. On failure returns NULL and throws an exception.
8043 mono_load_remote_field_new_icall (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
8046 MonoObject *result = mono_load_remote_field_new_checked (this_obj, klass, field, &error);
8047 mono_error_set_pending_exception (&error);
8052 * mono_load_remote_field_new_checked:
8053 * @this: pointer to an object
8054 * @klass: klass of the object containing @field
8055 * @field: the field to load
8056 * @error: set on error.
8058 * This method is called by the runtime on attempts to load fields of
8059 * transparent proxy objects. @this points to such TP, @klass is the class of
8060 * the object containing @field.
8062 * Returns: a freshly allocated object containing the value of the field. On failure returns NULL and sets @error.
8065 mono_load_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoError *error)
8067 MONO_REQ_GC_UNSAFE_MODE;
8069 mono_error_init (error);
8071 static MonoMethod *getter = NULL;
8072 MonoDomain *domain = mono_domain_get ();
8073 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8074 MonoClass *field_class;
8075 MonoMethodMessage *msg;
8076 MonoArray *out_args;
8077 MonoObject *exc, *res;
8080 g_assert (mono_object_is_transparent_proxy (this_obj));
8082 field_class = mono_class_from_mono_type (field->type);
8084 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8086 if (field_class->valuetype) {
8087 res = mono_object_new_checked (domain, field_class, error);
8088 return_val_if_nok (error, NULL);
8089 val = ((gchar *) res) + sizeof (MonoObject);
8093 mono_field_get_value (tp->rp->unwrapped_server, field, val);
8098 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
8100 mono_error_set_not_supported (error, "Linked away.");
8105 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8106 return_val_if_nok (error, NULL);
8107 out_args = mono_array_new_checked (domain, mono_defaults.object_class, 1, error);
8108 return_val_if_nok (error, NULL);
8110 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, error);
8111 return_val_if_nok (error, NULL);
8112 mono_message_init (domain, msg, rm, out_args, error);
8113 return_val_if_nok (error, NULL);
8115 full_name = mono_type_get_full_name (klass);
8116 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
8117 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
8120 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8121 return_val_if_nok (error, NULL);
8124 mono_error_set_exception_instance (error, (MonoException *)exc);
8128 if (mono_array_length (out_args) == 0)
8131 res = mono_array_get (out_args, MonoObject *, 0);
8137 * mono_store_remote_field:
8138 * @this_obj: pointer to an object
8139 * @klass: klass of the object containing @field
8140 * @field: the field to load
8141 * @val: the value/object to store
8143 * This method is called by the runtime on attempts to store fields of
8144 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
8145 * the object containing @field. @val is the new value to store in @field.
8148 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
8151 (void) mono_store_remote_field_checked (this_obj, klass, field, val, &error);
8152 mono_error_cleanup (&error);
8156 * mono_store_remote_field_checked:
8157 * @this_obj: pointer to an object
8158 * @klass: klass of the object containing @field
8159 * @field: the field to load
8160 * @val: the value/object to store
8161 * @error: set on error
8163 * This method is called by the runtime on attempts to store fields of
8164 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
8165 * the object containing @field. @val is the new value to store in @field.
8167 * Returns: on success returns TRUE, on failure returns FALSE and sets @error.
8170 mono_store_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val, MonoError *error)
8173 MONO_REQ_GC_UNSAFE_MODE;
8175 static MonoMethod *setter = NULL;
8177 MonoDomain *domain = mono_domain_get ();
8178 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8179 MonoClass *field_class;
8180 MonoMethodMessage *msg;
8181 MonoArray *out_args;
8186 mono_error_init (error);
8188 g_assert (mono_object_is_transparent_proxy (this_obj));
8190 field_class = mono_class_from_mono_type (field->type);
8192 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8193 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
8194 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
8199 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
8201 mono_error_set_not_supported (error, "Linked away.");
8206 if (field_class->valuetype) {
8207 arg = mono_value_box_checked (domain, field_class, val, error);
8208 return_val_if_nok (error, FALSE);
8210 arg = *((MonoObject **)val);
8213 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8214 return_val_if_nok (error, FALSE);
8215 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, setter, NULL, error);
8216 return_val_if_nok (error, FALSE);
8217 mono_message_init (domain, msg, rm, NULL, error);
8218 return_val_if_nok (error, FALSE);
8220 full_name = mono_type_get_full_name (klass);
8221 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
8222 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
8223 mono_array_setref (msg->args, 2, arg);
8226 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8227 return_val_if_nok (error, FALSE);
8230 mono_error_set_exception_instance (error, (MonoException *)exc);
8237 * mono_store_remote_field_new:
8243 * Missing documentation
8246 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
8249 (void) mono_store_remote_field_new_checked (this_obj, klass, field, arg, &error);
8250 mono_error_cleanup (&error);
8254 * mono_store_remote_field_new_icall:
8260 * Missing documentation
8263 mono_store_remote_field_new_icall (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
8266 (void) mono_store_remote_field_new_checked (this_obj, klass, field, arg, &error);
8267 mono_error_set_pending_exception (&error);
8271 * mono_store_remote_field_new_checked:
8278 * Missing documentation
8281 mono_store_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg, MonoError *error)
8283 MONO_REQ_GC_UNSAFE_MODE;
8285 static MonoMethod *setter = NULL;
8286 MonoDomain *domain = mono_domain_get ();
8287 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8288 MonoClass *field_class;
8289 MonoMethodMessage *msg;
8290 MonoArray *out_args;
8294 mono_error_init (error);
8296 g_assert (mono_object_is_transparent_proxy (this_obj));
8298 field_class = mono_class_from_mono_type (field->type);
8300 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8301 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
8302 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
8307 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
8309 mono_error_set_not_supported (error, "Linked away.");
8314 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8315 return_val_if_nok (error, FALSE);
8316 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, setter, NULL, error);
8317 return_val_if_nok (error, FALSE);
8318 mono_message_init (domain, msg, rm, NULL, error);
8319 return_val_if_nok (error, FALSE);
8321 full_name = mono_type_get_full_name (klass);
8322 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
8323 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
8324 mono_array_setref (msg->args, 2, arg);
8327 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8328 return_val_if_nok (error, FALSE);
8331 mono_error_set_exception_instance (error, (MonoException *)exc);
8339 * mono_create_ftnptr:
8341 * Given a function address, create a function descriptor for it.
8342 * This is only needed on some platforms.
8345 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
8347 return callbacks.create_ftnptr (domain, addr);
8351 * mono_get_addr_from_ftnptr:
8353 * Given a pointer to a function descriptor, return the function address.
8354 * This is only needed on some platforms.
8357 mono_get_addr_from_ftnptr (gpointer descr)
8359 return callbacks.get_addr_from_ftnptr (descr);
8363 * mono_string_chars:
8366 * Returns a pointer to the UCS16 characters stored in the MonoString
8369 mono_string_chars (MonoString *s)
8371 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
8377 * mono_string_length:
8380 * Returns the lenght in characters of the string
8383 mono_string_length (MonoString *s)
8385 MONO_REQ_GC_UNSAFE_MODE;
8391 * mono_array_length:
8392 * @array: a MonoArray*
8394 * Returns the total number of elements in the array. This works for
8395 * both vectors and multidimensional arrays.
8398 mono_array_length (MonoArray *array)
8400 MONO_REQ_GC_UNSAFE_MODE;
8402 return array->max_length;
8406 * mono_array_addr_with_size:
8407 * @array: a MonoArray*
8408 * @size: size of the array elements
8409 * @idx: index into the array
8411 * Use this function to obtain the address for the @idx item on the
8412 * @array containing elements of size @size.
8414 * This method performs no bounds checking or type checking.
8416 * Returns the address of the @idx element in the array.
8419 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
8421 MONO_REQ_GC_UNSAFE_MODE;
8423 return ((char*)(array)->vector) + size * idx;
8428 mono_glist_to_array (GList *list, MonoClass *eclass, MonoError *error)
8430 MonoDomain *domain = mono_domain_get ();
8434 mono_error_init (error);
8438 len = g_list_length (list);
8439 res = mono_array_new_checked (domain, eclass, len, error);
8440 return_val_if_nok (error, NULL);
8442 for (i = 0; list; list = list->next, i++)
8443 mono_array_set (res, gpointer, i, list->data);
8450 * The following section is purely to declare prototypes and
8451 * document the API, as these C files are processed by our
8457 * @array: array to alter
8458 * @element_type: A C type name, this macro will use the sizeof(type) to determine the element size
8459 * @index: index into the array
8460 * @value: value to set
8462 * Value Type version: This sets the @index's element of the @array
8463 * with elements of size sizeof(type) to the provided @value.
8465 * This macro does not attempt to perform type checking or bounds checking.
8467 * Use this to set value types in a `MonoArray`.
8469 void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
8474 * mono_array_setref:
8475 * @array: array to alter
8476 * @index: index into the array
8477 * @value: value to set
8479 * Reference Type version: This sets the @index's element of the
8480 * @array with elements of size sizeof(type) to the provided @value.
8482 * This macro does not attempt to perform type checking or bounds checking.
8484 * Use this to reference types in a `MonoArray`.
8486 void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
8492 * @array: array on which to operate on
8493 * @element_type: C element type (example: MonoString *, int, MonoObject *)
8494 * @index: index into the array
8496 * Use this macro to retrieve the @index element of an @array and
8497 * extract the value assuming that the elements of the array match
8498 * the provided type value.
8500 * This method can be used with both arrays holding value types and
8501 * reference types. For reference types, the @type parameter should
8502 * be a `MonoObject*` or any subclass of it, like `MonoString*`.
8504 * This macro does not attempt to perform type checking or bounds checking.
8506 * Returns: The element at the @index position in the @array.
8508 Type mono_array_get (MonoArray *array, Type element_type, uintptr_t index)