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)
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
2309 * Creates a vtable for transparent proxies. It is basically
2310 * a copy of the real vtable of the class wrapped in @remote_class,
2311 * but all function pointers invoke the remoting functions, and
2312 * vtable->klass points to the transparent proxy class, and not to @class.
2315 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2317 MONO_REQ_GC_UNSAFE_MODE;
2320 MonoVTable *vt, *pvt;
2321 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2323 GSList *extra_interfaces = NULL;
2324 MonoClass *klass = remote_class->proxy_class;
2325 gpointer *interface_offsets;
2328 size_t imt_table_bytes;
2330 #ifdef COMPRESSED_INTERFACE_BITMAP
2334 vt = mono_class_vtable (domain, klass);
2335 g_assert (vt); /*FIXME property handle failure*/
2336 max_interface_id = vt->max_interface_id;
2338 /* Calculate vtable space for extra interfaces */
2339 for (j = 0; j < remote_class->interface_count; j++) {
2340 MonoClass* iclass = remote_class->interfaces[j];
2344 /*FIXME test for interfaces with variant generic arguments*/
2345 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, iclass->interface_id))
2346 continue; /* interface implemented by the class */
2347 if (g_slist_find (extra_interfaces, iclass))
2350 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2352 method_count = mono_class_num_methods (iclass);
2354 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2355 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2357 for (i = 0; i < ifaces->len; ++i) {
2358 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2359 /*FIXME test for interfaces with variant generic arguments*/
2360 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, ic->interface_id))
2361 continue; /* interface implemented by the class */
2362 if (g_slist_find (extra_interfaces, ic))
2364 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2365 method_count += mono_class_num_methods (ic);
2367 g_ptr_array_free (ifaces, TRUE);
2370 extra_interface_vtsize += method_count * sizeof (gpointer);
2371 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2374 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2375 mono_stats.imt_number_of_tables++;
2376 mono_stats.imt_tables_size += imt_table_bytes;
2378 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer);
2380 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2382 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2383 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2384 g_assert (!((gsize)pvt & 7));
2386 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer));
2388 pvt->klass = mono_defaults.transparent_proxy_class;
2389 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2390 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2392 /* initialize vtable */
2393 mono_class_setup_vtable (klass);
2394 for (i = 0; i < klass->vtable_size; ++i) {
2397 if ((cm = klass->vtable [i]))
2398 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2400 pvt->vtable [i] = NULL;
2403 if (klass->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2404 /* create trampolines for abstract methods */
2405 for (k = klass; k; k = k->parent) {
2407 gpointer iter = NULL;
2408 while ((m = mono_class_get_methods (k, &iter)))
2409 if (!pvt->vtable [m->slot])
2410 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2414 pvt->max_interface_id = max_interface_id;
2415 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2416 #ifdef COMPRESSED_INTERFACE_BITMAP
2417 bitmap = (uint8_t *)g_malloc0 (bsize);
2419 bitmap = (uint8_t *)mono_domain_alloc0 (domain, bsize);
2422 for (i = 0; i < klass->interface_offsets_count; ++i) {
2423 int interface_id = klass->interfaces_packed [i]->interface_id;
2424 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2427 if (extra_interfaces) {
2428 int slot = klass->vtable_size;
2434 /* Create trampolines for the methods of the interfaces */
2435 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2436 interf = (MonoClass *)list_item->data;
2438 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2442 while ((cm = mono_class_get_methods (interf, &iter)))
2443 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2445 slot += mono_class_num_methods (interf);
2449 /* Now that the vtable is full, we can actually fill up the IMT */
2450 build_imt (klass, pvt, domain, interface_offsets, extra_interfaces);
2451 if (extra_interfaces) {
2452 g_slist_free (extra_interfaces);
2455 #ifdef COMPRESSED_INTERFACE_BITMAP
2456 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2457 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2458 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2461 pvt->interface_bitmap = bitmap;
2466 #endif /* DISABLE_REMOTING */
2469 * mono_class_field_is_special_static:
2471 * Returns whether @field is a thread/context static field.
2474 mono_class_field_is_special_static (MonoClassField *field)
2476 MONO_REQ_GC_NEUTRAL_MODE
2478 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2480 if (mono_field_is_deleted (field))
2482 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2483 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2490 * mono_class_field_get_special_static_type:
2491 * @field: The MonoClassField describing the field.
2493 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2494 * SPECIAL_STATIC_NONE otherwise.
2497 mono_class_field_get_special_static_type (MonoClassField *field)
2499 MONO_REQ_GC_NEUTRAL_MODE
2501 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2502 return SPECIAL_STATIC_NONE;
2503 if (mono_field_is_deleted (field))
2504 return SPECIAL_STATIC_NONE;
2505 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2506 return field_is_special_static (field->parent, field);
2507 return SPECIAL_STATIC_NONE;
2511 * mono_class_has_special_static_fields:
2513 * Returns whenever @klass has any thread/context static fields.
2516 mono_class_has_special_static_fields (MonoClass *klass)
2518 MONO_REQ_GC_NEUTRAL_MODE
2520 MonoClassField *field;
2524 while ((field = mono_class_get_fields (klass, &iter))) {
2525 g_assert (field->parent == klass);
2526 if (mono_class_field_is_special_static (field))
2533 #ifndef DISABLE_REMOTING
2535 * create_remote_class_key:
2536 * Creates an array of pointers that can be used as a hash key for a remote class.
2537 * The first element of the array is the number of pointers.
2540 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2542 MONO_REQ_GC_NEUTRAL_MODE;
2547 if (remote_class == NULL) {
2548 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2549 key = (void **)g_malloc (sizeof(gpointer) * 3);
2550 key [0] = GINT_TO_POINTER (2);
2551 key [1] = mono_defaults.marshalbyrefobject_class;
2552 key [2] = extra_class;
2554 key = (void **)g_malloc (sizeof(gpointer) * 2);
2555 key [0] = GINT_TO_POINTER (1);
2556 key [1] = extra_class;
2559 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2560 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2561 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2562 key [1] = remote_class->proxy_class;
2564 // Keep the list of interfaces sorted
2565 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2566 if (extra_class && remote_class->interfaces [i] > extra_class) {
2567 key [j++] = extra_class;
2570 key [j] = remote_class->interfaces [i];
2573 key [j] = extra_class;
2575 // Replace the old class. The interface list is the same
2576 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2577 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2578 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2579 for (i = 0; i < remote_class->interface_count; i++)
2580 key [2 + i] = remote_class->interfaces [i];
2588 * copy_remote_class_key:
2590 * Make a copy of KEY in the domain and return the copy.
2593 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2595 MONO_REQ_GC_NEUTRAL_MODE
2597 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2598 gpointer *mp_key = (gpointer *)mono_domain_alloc (domain, key_size);
2600 memcpy (mp_key, key, key_size);
2606 * mono_remote_class:
2607 * @domain: the application domain
2608 * @class_name: name of the remote class
2609 * @error: set on error
2611 * Creates and initializes a MonoRemoteClass object for a remote type.
2613 * On failure returns NULL and sets @error
2616 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class, MonoError *error)
2618 MONO_REQ_GC_UNSAFE_MODE;
2620 MonoRemoteClass *rc;
2621 gpointer* key, *mp_key;
2624 mono_error_init (error);
2626 key = create_remote_class_key (NULL, proxy_class);
2628 mono_domain_lock (domain);
2629 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2633 mono_domain_unlock (domain);
2637 name = mono_string_to_utf8_mp (domain->mp, class_name, error);
2638 if (!is_ok (error)) {
2640 mono_domain_unlock (domain);
2644 mp_key = copy_remote_class_key (domain, key);
2648 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2649 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2650 rc->interface_count = 1;
2651 rc->interfaces [0] = proxy_class;
2652 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2654 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2655 rc->interface_count = 0;
2656 rc->proxy_class = proxy_class;
2659 rc->default_vtable = NULL;
2660 rc->xdomain_vtable = NULL;
2661 rc->proxy_class_name = name;
2662 #ifndef DISABLE_PERFCOUNTERS
2663 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2666 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2668 mono_domain_unlock (domain);
2673 * clone_remote_class:
2674 * Creates a copy of the remote_class, adding the provided class or interface
2676 static MonoRemoteClass*
2677 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2679 MONO_REQ_GC_NEUTRAL_MODE;
2681 MonoRemoteClass *rc;
2682 gpointer* key, *mp_key;
2684 key = create_remote_class_key (remote_class, extra_class);
2685 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2691 mp_key = copy_remote_class_key (domain, key);
2695 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2697 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2698 rc->proxy_class = remote_class->proxy_class;
2699 rc->interface_count = remote_class->interface_count + 1;
2701 // Keep the list of interfaces sorted, since the hash key of
2702 // the remote class depends on this
2703 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2704 if (remote_class->interfaces [i] > extra_class && i == j)
2705 rc->interfaces [j++] = extra_class;
2706 rc->interfaces [j] = remote_class->interfaces [i];
2709 rc->interfaces [j] = extra_class;
2711 // Replace the old class. The interface array is the same
2712 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2713 rc->proxy_class = extra_class;
2714 rc->interface_count = remote_class->interface_count;
2715 if (rc->interface_count > 0)
2716 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2719 rc->default_vtable = NULL;
2720 rc->xdomain_vtable = NULL;
2721 rc->proxy_class_name = remote_class->proxy_class_name;
2723 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2729 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2731 MONO_REQ_GC_UNSAFE_MODE;
2733 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2734 mono_domain_lock (domain);
2735 if (rp->target_domain_id != -1) {
2736 if (remote_class->xdomain_vtable == NULL)
2737 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2738 mono_domain_unlock (domain);
2739 mono_loader_unlock ();
2740 return remote_class->xdomain_vtable;
2742 if (remote_class->default_vtable == NULL) {
2745 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2746 klass = mono_class_from_mono_type (type);
2748 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)))
2749 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2752 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2755 mono_domain_unlock (domain);
2756 mono_loader_unlock ();
2757 return remote_class->default_vtable;
2761 * mono_upgrade_remote_class:
2762 * @domain: the application domain
2763 * @tproxy: the proxy whose remote class has to be upgraded.
2764 * @klass: class to which the remote class can be casted.
2766 * Updates the vtable of the remote class by adding the necessary method slots
2767 * and interface offsets so it can be safely casted to klass. klass can be a
2768 * class or an interface.
2771 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2773 MONO_REQ_GC_UNSAFE_MODE;
2775 MonoTransparentProxy *tproxy;
2776 MonoRemoteClass *remote_class;
2777 gboolean redo_vtable;
2779 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2780 mono_domain_lock (domain);
2782 tproxy = (MonoTransparentProxy*) proxy_object;
2783 remote_class = tproxy->remote_class;
2785 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2788 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2789 if (remote_class->interfaces [i] == klass)
2790 redo_vtable = FALSE;
2793 redo_vtable = (remote_class->proxy_class != klass);
2797 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2798 proxy_object->vtable = (MonoVTable *)mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2801 mono_domain_unlock (domain);
2802 mono_loader_unlock ();
2804 #endif /* DISABLE_REMOTING */
2808 * mono_object_get_virtual_method:
2809 * @obj: object to operate on.
2812 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2813 * the instance of a callvirt of method.
2816 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2818 MONO_REQ_GC_UNSAFE_MODE;
2821 MonoMethod **vtable;
2822 gboolean is_proxy = FALSE;
2823 MonoMethod *res = NULL;
2825 klass = mono_object_class (obj);
2826 #ifndef DISABLE_REMOTING
2827 if (klass == mono_defaults.transparent_proxy_class) {
2828 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2833 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2836 mono_class_setup_vtable (klass);
2837 vtable = klass->vtable;
2839 if (method->slot == -1) {
2840 /* method->slot might not be set for instances of generic methods */
2841 if (method->is_inflated) {
2842 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2843 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2846 g_assert_not_reached ();
2850 /* check method->slot is a valid index: perform isinstance? */
2851 if (method->slot != -1) {
2852 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2854 gboolean variance_used = FALSE;
2855 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2856 g_assert (iface_offset > 0);
2857 res = vtable [iface_offset + method->slot];
2860 res = vtable [method->slot];
2864 #ifndef DISABLE_REMOTING
2866 /* It may be an interface, abstract class method or generic method */
2867 if (!res || mono_method_signature (res)->generic_param_count)
2870 /* generic methods demand invoke_with_check */
2871 if (mono_method_signature (res)->generic_param_count)
2872 res = mono_marshal_get_remoting_invoke_with_check (res);
2875 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2876 res = mono_cominterop_get_invoke (res);
2879 res = mono_marshal_get_remoting_invoke (res);
2884 if (method->is_inflated) {
2886 /* Have to inflate the result */
2887 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, &error);
2888 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
2898 do_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2900 MONO_REQ_GC_UNSAFE_MODE;
2902 MonoObject *result = NULL;
2904 g_assert (callbacks.runtime_invoke);
2906 mono_error_init (error);
2908 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2909 mono_profiler_method_start_invoke (method);
2911 MONO_ENTER_GC_UNSAFE;
2913 result = callbacks.runtime_invoke (method, obj, params, exc, error);
2915 MONO_EXIT_GC_UNSAFE;
2917 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2918 mono_profiler_method_end_invoke (method);
2920 if (!mono_error_ok (error))
2927 * mono_runtime_invoke:
2928 * @method: method to invoke
2929 * @obJ: object instance
2930 * @params: arguments to the method
2931 * @exc: exception information.
2933 * Invokes the method represented by @method on the object @obj.
2935 * obj is the 'this' pointer, it should be NULL for static
2936 * methods, a MonoObject* for object instances and a pointer to
2937 * the value type for value types.
2939 * The params array contains the arguments to the method with the
2940 * same convention: MonoObject* pointers for object instances and
2941 * pointers to the value type otherwise.
2943 * From unmanaged code you'll usually use the
2944 * mono_runtime_invoke() variant.
2946 * Note that this function doesn't handle virtual methods for
2947 * you, it will exec the exact method you pass: we still need to
2948 * expose a function to lookup the derived class implementation
2949 * of a virtual method (there are examples of this in the code,
2952 * You can pass NULL as the exc argument if you don't want to
2953 * catch exceptions, otherwise, *exc will be set to the exception
2954 * thrown, if any. if an exception is thrown, you can't use the
2955 * MonoObject* result from the function.
2957 * If the method returns a value type, it is boxed in an object
2961 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2966 res = mono_runtime_try_invoke (method, obj, params, exc, &error);
2967 if (*exc == NULL && !mono_error_ok(&error)) {
2968 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
2970 mono_error_cleanup (&error);
2972 res = mono_runtime_invoke_checked (method, obj, params, &error);
2973 mono_error_raise_exception (&error);
2979 * mono_runtime_try_invoke:
2980 * @method: method to invoke
2981 * @obJ: object instance
2982 * @params: arguments to the method
2983 * @exc: exception information.
2984 * @error: set on error
2986 * Invokes the method represented by @method on the object @obj.
2988 * obj is the 'this' pointer, it should be NULL for static
2989 * methods, a MonoObject* for object instances and a pointer to
2990 * the value type for value types.
2992 * The params array contains the arguments to the method with the
2993 * same convention: MonoObject* pointers for object instances and
2994 * pointers to the value type otherwise.
2996 * From unmanaged code you'll usually use the
2997 * mono_runtime_invoke() variant.
2999 * Note that this function doesn't handle virtual methods for
3000 * you, it will exec the exact method you pass: we still need to
3001 * expose a function to lookup the derived class implementation
3002 * of a virtual method (there are examples of this in the code,
3005 * For this function, you must not pass NULL as the exc argument if
3006 * you don't want to catch exceptions, use
3007 * mono_runtime_invoke_checked(). If an exception is thrown, you
3008 * can't use the MonoObject* result from the function.
3010 * If this method cannot be invoked, @error will be set and @exc and
3011 * the return value must not be used.
3013 * If the method returns a value type, it is boxed in an object
3017 mono_runtime_try_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError* error)
3019 MONO_REQ_GC_UNSAFE_MODE;
3021 g_assert (exc != NULL);
3023 if (mono_runtime_get_no_exec ())
3024 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
3026 return do_runtime_invoke (method, obj, params, exc, error);
3030 * mono_runtime_invoke_checked:
3031 * @method: method to invoke
3032 * @obJ: object instance
3033 * @params: arguments to the method
3034 * @error: set on error
3036 * Invokes the method represented by @method on the object @obj.
3038 * obj is the 'this' pointer, it should be NULL for static
3039 * methods, a MonoObject* for object instances and a pointer to
3040 * the value type for value types.
3042 * The params array contains the arguments to the method with the
3043 * same convention: MonoObject* pointers for object instances and
3044 * pointers to the value type otherwise.
3046 * From unmanaged code you'll usually use the
3047 * mono_runtime_invoke() variant.
3049 * Note that this function doesn't handle virtual methods for
3050 * you, it will exec the exact method you pass: we still need to
3051 * expose a function to lookup the derived class implementation
3052 * of a virtual method (there are examples of this in the code,
3055 * If an exception is thrown, you can't use the MonoObject* result
3056 * from the function.
3058 * If this method cannot be invoked, @error will be set. If the
3059 * method throws an exception (and we're in coop mode) the exception
3060 * will be set in @error.
3062 * If the method returns a value type, it is boxed in an object
3066 mono_runtime_invoke_checked (MonoMethod *method, void *obj, void **params, MonoError* error)
3068 MONO_REQ_GC_UNSAFE_MODE;
3070 if (mono_runtime_get_no_exec ())
3071 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
3073 return do_runtime_invoke (method, obj, params, NULL, error);
3077 * mono_method_get_unmanaged_thunk:
3078 * @method: method to generate a thunk for.
3080 * Returns an unmanaged->managed thunk that can be used to call
3081 * a managed method directly from C.
3083 * The thunk's C signature closely matches the managed signature:
3085 * C#: public bool Equals (object obj);
3086 * C: typedef MonoBoolean (*Equals)(MonoObject*,
3087 * MonoObject*, MonoException**);
3089 * The 1st ("this") parameter must not be used with static methods:
3091 * C#: public static bool ReferenceEquals (object a, object b);
3092 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
3095 * The last argument must be a non-null pointer of a MonoException* pointer.
3096 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
3097 * exception has been thrown in managed code. Otherwise it will point
3098 * to the MonoException* caught by the thunk. In this case, the result of
3099 * the thunk is undefined:
3101 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
3102 * MonoException *ex = NULL;
3103 * Equals func = mono_method_get_unmanaged_thunk (method);
3104 * MonoBoolean res = func (thisObj, objToCompare, &ex);
3106 * // handle exception
3109 * The calling convention of the thunk matches the platform's default
3110 * convention. This means that under Windows, C declarations must
3111 * contain the __stdcall attribute:
3113 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
3114 * MonoObject*, MonoException**);
3118 * Value type arguments and return values are treated as they were objects:
3120 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
3121 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
3123 * Arguments must be properly boxed upon trunk's invocation, while return
3124 * values must be unboxed.
3127 mono_method_get_unmanaged_thunk (MonoMethod *method)
3129 MONO_REQ_GC_NEUTRAL_MODE;
3130 MONO_REQ_API_ENTRYPOINT;
3135 g_assert (!mono_threads_is_coop_enabled ());
3137 MONO_ENTER_GC_UNSAFE;
3138 method = mono_marshal_get_thunk_invoke_wrapper (method);
3139 res = mono_compile_method_checked (method, &error);
3140 mono_error_cleanup (&error);
3141 MONO_EXIT_GC_UNSAFE;
3147 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
3149 MONO_REQ_GC_UNSAFE_MODE;
3153 /* object fields cannot be byref, so we don't need a
3155 gpointer *p = (gpointer*)dest;
3162 case MONO_TYPE_BOOLEAN:
3164 case MONO_TYPE_U1: {
3165 guint8 *p = (guint8*)dest;
3166 *p = value ? *(guint8*)value : 0;
3171 case MONO_TYPE_CHAR: {
3172 guint16 *p = (guint16*)dest;
3173 *p = value ? *(guint16*)value : 0;
3176 #if SIZEOF_VOID_P == 4
3181 case MONO_TYPE_U4: {
3182 gint32 *p = (gint32*)dest;
3183 *p = value ? *(gint32*)value : 0;
3186 #if SIZEOF_VOID_P == 8
3191 case MONO_TYPE_U8: {
3192 gint64 *p = (gint64*)dest;
3193 *p = value ? *(gint64*)value : 0;
3196 case MONO_TYPE_R4: {
3197 float *p = (float*)dest;
3198 *p = value ? *(float*)value : 0;
3201 case MONO_TYPE_R8: {
3202 double *p = (double*)dest;
3203 *p = value ? *(double*)value : 0;
3206 case MONO_TYPE_STRING:
3207 case MONO_TYPE_SZARRAY:
3208 case MONO_TYPE_CLASS:
3209 case MONO_TYPE_OBJECT:
3210 case MONO_TYPE_ARRAY:
3211 mono_gc_wbarrier_generic_store (dest, deref_pointer ? *(MonoObject **)value : (MonoObject *)value);
3213 case MONO_TYPE_FNPTR:
3214 case MONO_TYPE_PTR: {
3215 gpointer *p = (gpointer*)dest;
3216 *p = deref_pointer? *(gpointer*)value: value;
3219 case MONO_TYPE_VALUETYPE:
3220 /* note that 't' and 'type->type' can be different */
3221 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3222 t = mono_class_enum_basetype (type->data.klass)->type;
3225 MonoClass *klass = mono_class_from_mono_type (type);
3226 int size = mono_class_value_size (klass, NULL);
3228 mono_gc_bzero_atomic (dest, size);
3230 mono_gc_wbarrier_value_copy (dest, value, 1, klass);
3233 case MONO_TYPE_GENERICINST:
3234 t = type->data.generic_class->container_class->byval_arg.type;
3237 g_error ("got type %x", type->type);
3242 * mono_field_set_value:
3243 * @obj: Instance object
3244 * @field: MonoClassField describing the field to set
3245 * @value: The value to be set
3247 * Sets the value of the field described by @field in the object instance @obj
3248 * to the value passed in @value. This method should only be used for instance
3249 * fields. For static fields, use mono_field_static_set_value.
3251 * The value must be on the native format of the field type.
3254 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3256 MONO_REQ_GC_UNSAFE_MODE;
3260 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3262 dest = (char*)obj + field->offset;
3263 mono_copy_value (field->type, dest, value, FALSE);
3267 * mono_field_static_set_value:
3268 * @field: MonoClassField describing the field to set
3269 * @value: The value to be set
3271 * Sets the value of the static field described by @field
3272 * to the value passed in @value.
3274 * The value must be on the native format of the field type.
3277 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3279 MONO_REQ_GC_UNSAFE_MODE;
3283 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3284 /* you cant set a constant! */
3285 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3287 if (field->offset == -1) {
3288 /* Special static */
3291 mono_domain_lock (vt->domain);
3292 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3293 mono_domain_unlock (vt->domain);
3294 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3296 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3298 mono_copy_value (field->type, dest, value, FALSE);
3302 * mono_vtable_get_static_field_data:
3304 * Internal use function: return a pointer to the memory holding the static fields
3305 * for a class or NULL if there are no static fields.
3306 * This is exported only for use by the debugger.
3309 mono_vtable_get_static_field_data (MonoVTable *vt)
3311 MONO_REQ_GC_NEUTRAL_MODE
3313 if (!vt->has_static_fields)
3315 return vt->vtable [vt->klass->vtable_size];
3319 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3321 MONO_REQ_GC_UNSAFE_MODE;
3325 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3326 if (field->offset == -1) {
3327 /* Special static */
3330 mono_domain_lock (vt->domain);
3331 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3332 mono_domain_unlock (vt->domain);
3333 src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3335 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3338 src = (guint8*)obj + field->offset;
3345 * mono_field_get_value:
3346 * @obj: Object instance
3347 * @field: MonoClassField describing the field to fetch information from
3348 * @value: pointer to the location where the value will be stored
3350 * Use this routine to get the value of the field @field in the object
3353 * The pointer provided by value must be of the field type, for reference
3354 * types this is a MonoObject*, for value types its the actual pointer to
3359 * mono_field_get_value (obj, int_field, &i);
3362 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3364 MONO_REQ_GC_UNSAFE_MODE;
3370 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3372 src = (char*)obj + field->offset;
3373 mono_copy_value (field->type, value, src, TRUE);
3377 * mono_field_get_value_object:
3378 * @domain: domain where the object will be created (if boxing)
3379 * @field: MonoClassField describing the field to fetch information from
3380 * @obj: The object instance for the field.
3382 * Returns: a new MonoObject with the value from the given field. If the
3383 * field represents a value type, the value is boxed.
3387 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3390 MonoObject* result = mono_field_get_value_object_checked (domain, field, obj, &error);
3391 mono_error_assert_ok (&error);
3396 * mono_field_get_value_object_checked:
3397 * @domain: domain where the object will be created (if boxing)
3398 * @field: MonoClassField describing the field to fetch information from
3399 * @obj: The object instance for the field.
3400 * @error: Set on error.
3402 * Returns: a new MonoObject with the value from the given field. If the
3403 * field represents a value type, the value is boxed. On error returns NULL and sets @error.
3407 mono_field_get_value_object_checked (MonoDomain *domain, MonoClassField *field, MonoObject *obj, MonoError *error)
3409 MONO_REQ_GC_UNSAFE_MODE;
3411 mono_error_init (error);
3415 MonoVTable *vtable = NULL;
3417 gboolean is_static = FALSE;
3418 gboolean is_ref = FALSE;
3419 gboolean is_literal = FALSE;
3420 gboolean is_ptr = FALSE;
3421 MonoType *type = mono_field_get_type_checked (field, error);
3423 return_val_if_nok (error, NULL);
3425 switch (type->type) {
3426 case MONO_TYPE_STRING:
3427 case MONO_TYPE_OBJECT:
3428 case MONO_TYPE_CLASS:
3429 case MONO_TYPE_ARRAY:
3430 case MONO_TYPE_SZARRAY:
3435 case MONO_TYPE_BOOLEAN:
3438 case MONO_TYPE_CHAR:
3447 case MONO_TYPE_VALUETYPE:
3448 is_ref = type->byref;
3450 case MONO_TYPE_GENERICINST:
3451 is_ref = !mono_type_generic_inst_is_valuetype (type);
3457 g_error ("type 0x%x not handled in "
3458 "mono_field_get_value_object", type->type);
3462 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3465 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3469 vtable = mono_class_vtable_full (domain, field->parent, error);
3470 return_val_if_nok (error, NULL);
3472 if (!vtable->initialized) {
3473 mono_runtime_class_init_full (vtable, error);
3474 return_val_if_nok (error, NULL);
3483 get_default_field_value (domain, field, &o, error);
3484 return_val_if_nok (error, NULL);
3485 } else if (is_static) {
3486 mono_field_static_get_value_checked (vtable, field, &o, error);
3487 return_val_if_nok (error, NULL);
3489 mono_field_get_value (obj, field, &o);
3495 static MonoMethod *m;
3501 MonoClass *ptr_klass = mono_class_get_pointer_class ();
3502 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3508 get_default_field_value (domain, field, v, error);
3509 return_val_if_nok (error, NULL);
3510 } else if (is_static) {
3511 mono_field_static_get_value_checked (vtable, field, v, error);
3512 return_val_if_nok (error, NULL);
3514 mono_field_get_value (obj, field, v);
3517 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3518 args [0] = ptr ? *ptr : NULL;
3519 args [1] = mono_type_get_object_checked (mono_domain_get (), type, error);
3520 return_val_if_nok (error, NULL);
3522 o = mono_runtime_invoke_checked (m, NULL, args, error);
3523 return_val_if_nok (error, NULL);
3528 /* boxed value type */
3529 klass = mono_class_from_mono_type (type);
3531 if (mono_class_is_nullable (klass))
3532 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass, error);
3534 o = mono_object_new_checked (domain, klass, error);
3535 return_val_if_nok (error, NULL);
3536 v = ((gchar *) o) + sizeof (MonoObject);
3539 get_default_field_value (domain, field, v, error);
3540 return_val_if_nok (error, NULL);
3541 } else if (is_static) {
3542 mono_field_static_get_value_checked (vtable, field, v, error);
3543 return_val_if_nok (error, NULL);
3545 mono_field_get_value (obj, field, v);
3552 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value, MonoError *error)
3554 MONO_REQ_GC_UNSAFE_MODE;
3556 mono_error_init (error);
3558 const char *p = blob;
3559 mono_metadata_decode_blob_size (p, &p);
3562 case MONO_TYPE_BOOLEAN:
3565 *(guint8 *) value = *p;
3567 case MONO_TYPE_CHAR:
3570 *(guint16*) value = read16 (p);
3574 *(guint32*) value = read32 (p);
3578 *(guint64*) value = read64 (p);
3581 readr4 (p, (float*) value);
3584 readr8 (p, (double*) value);
3586 case MONO_TYPE_STRING:
3587 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob, error);
3589 case MONO_TYPE_CLASS:
3590 *(gpointer*) value = NULL;
3594 g_warning ("type 0x%02x should not be in constant table", type);
3600 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error)
3602 MONO_REQ_GC_NEUTRAL_MODE;
3604 MonoTypeEnum def_type;
3607 mono_error_init (error);
3609 data = mono_class_get_field_default_value (field, &def_type);
3610 mono_get_constant_value_from_blob (domain, def_type, data, value, error);
3614 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3616 MONO_REQ_GC_UNSAFE_MODE;
3620 mono_error_init (error);
3622 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3624 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3625 get_default_field_value (vt->domain, field, value, error);
3629 if (field->offset == -1) {
3630 /* Special static */
3631 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3632 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3634 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3636 mono_copy_value (field->type, value, src, TRUE);
3640 * mono_field_static_get_value:
3641 * @vt: vtable to the object
3642 * @field: MonoClassField describing the field to fetch information from
3643 * @value: where the value is returned
3645 * Use this routine to get the value of the static field @field value.
3647 * The pointer provided by value must be of the field type, for reference
3648 * types this is a MonoObject*, for value types its the actual pointer to
3653 * mono_field_static_get_value (vt, int_field, &i);
3656 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3658 MONO_REQ_GC_NEUTRAL_MODE;
3661 mono_field_static_get_value_checked (vt, field, value, &error);
3662 mono_error_cleanup (&error);
3666 * mono_field_static_get_value_checked:
3667 * @vt: vtable to the object
3668 * @field: MonoClassField describing the field to fetch information from
3669 * @value: where the value is returned
3670 * @error: set on error
3672 * Use this routine to get the value of the static field @field value.
3674 * The pointer provided by value must be of the field type, for reference
3675 * types this is a MonoObject*, for value types its the actual pointer to
3680 * mono_field_static_get_value_checked (vt, int_field, &i, error);
3681 * if (!is_ok (error)) { ... }
3683 * On failure sets @error.
3686 mono_field_static_get_value_checked (MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3688 MONO_REQ_GC_NEUTRAL_MODE;
3690 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value, error);
3694 * mono_property_set_value:
3695 * @prop: MonoProperty to set
3696 * @obj: instance object on which to act
3697 * @params: parameters to pass to the propery
3698 * @exc: optional exception
3700 * Invokes the property's set method with the given arguments on the
3701 * object instance obj (or NULL for static properties).
3703 * You can pass NULL as the exc argument if you don't want to
3704 * catch exceptions, otherwise, *exc will be set to the exception
3705 * thrown, if any. if an exception is thrown, you can't use the
3706 * MonoObject* result from the function.
3709 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3711 MONO_REQ_GC_UNSAFE_MODE;
3714 do_runtime_invoke (prop->set, obj, params, exc, &error);
3715 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3716 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3718 mono_error_cleanup (&error);
3723 * mono_property_set_value_checked:
3724 * @prop: MonoProperty to set
3725 * @obj: instance object on which to act
3726 * @params: parameters to pass to the propery
3727 * @error: set on error
3729 * Invokes the property's set method with the given arguments on the
3730 * object instance obj (or NULL for static properties).
3732 * Returns: TRUE on success. On failure returns FALSE and sets @error.
3733 * If an exception is thrown, it will be caught and returned via @error.
3736 mono_property_set_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3738 MONO_REQ_GC_UNSAFE_MODE;
3742 mono_error_init (error);
3743 do_runtime_invoke (prop->set, obj, params, &exc, error);
3744 if (exc != NULL && is_ok (error))
3745 mono_error_set_exception_instance (error, (MonoException*)exc);
3746 return is_ok (error);
3750 * mono_property_get_value:
3751 * @prop: MonoProperty to fetch
3752 * @obj: instance object on which to act
3753 * @params: parameters to pass to the propery
3754 * @exc: optional exception
3756 * Invokes the property's get method with the given arguments on the
3757 * object instance obj (or NULL for static properties).
3759 * You can pass NULL as the exc argument if you don't want to
3760 * catch exceptions, otherwise, *exc will be set to the exception
3761 * thrown, if any. if an exception is thrown, you can't use the
3762 * MonoObject* result from the function.
3764 * Returns: the value from invoking the get method on the property.
3767 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3769 MONO_REQ_GC_UNSAFE_MODE;
3772 MonoObject *val = do_runtime_invoke (prop->get, obj, params, exc, &error);
3773 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3774 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3776 mono_error_cleanup (&error); /* FIXME don't raise here */
3783 * mono_property_get_value_checked:
3784 * @prop: MonoProperty to fetch
3785 * @obj: instance object on which to act
3786 * @params: parameters to pass to the propery
3787 * @error: set on error
3789 * Invokes the property's get method with the given arguments on the
3790 * object instance obj (or NULL for static properties).
3792 * If an exception is thrown, you can't use the
3793 * MonoObject* result from the function. The exception will be propagated via @error.
3795 * Returns: the value from invoking the get method on the property. On
3796 * failure returns NULL and sets @error.
3799 mono_property_get_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3801 MONO_REQ_GC_UNSAFE_MODE;
3804 MonoObject *val = do_runtime_invoke (prop->get, obj, params, &exc, error);
3805 if (exc != NULL && !is_ok (error))
3806 mono_error_set_exception_instance (error, (MonoException*) exc);
3814 * mono_nullable_init:
3815 * @buf: The nullable structure to initialize.
3816 * @value: the value to initialize from
3817 * @klass: the type for the object
3819 * Initialize the nullable structure pointed to by @buf from @value which
3820 * should be a boxed value type. The size of @buf should be able to hold
3821 * as much data as the @klass->instance_size (which is the number of bytes
3822 * that will be copies).
3824 * Since Nullables have variable structure, we can not define a C
3825 * structure for them.
3828 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3830 MONO_REQ_GC_UNSAFE_MODE;
3832 MonoClass *param_class = klass->cast_class;
3834 mono_class_setup_fields_locking (klass);
3835 g_assert (klass->fields_inited);
3837 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3838 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3840 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3842 if (param_class->has_references)
3843 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3845 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3847 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3852 * mono_nullable_box:
3853 * @buf: The buffer representing the data to be boxed
3854 * @klass: the type to box it as.
3855 * @error: set on oerr
3857 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3858 * @buf. On failure returns NULL and sets @error
3861 mono_nullable_box (guint8 *buf, MonoClass *klass, MonoError *error)
3863 MONO_REQ_GC_UNSAFE_MODE;
3865 mono_error_init (error);
3866 MonoClass *param_class = klass->cast_class;
3868 mono_class_setup_fields_locking (klass);
3869 g_assert (klass->fields_inited);
3871 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3872 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3874 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3875 MonoObject *o = mono_object_new_checked (mono_domain_get (), param_class, error);
3876 return_val_if_nok (error, NULL);
3877 if (param_class->has_references)
3878 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3880 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3888 * mono_get_delegate_invoke:
3889 * @klass: The delegate class
3891 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3894 mono_get_delegate_invoke (MonoClass *klass)
3896 MONO_REQ_GC_NEUTRAL_MODE;
3900 /* This is called at runtime, so avoid the slower search in metadata */
3901 mono_class_setup_methods (klass);
3902 if (mono_class_has_failure (klass))
3904 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3909 * mono_get_delegate_begin_invoke:
3910 * @klass: The delegate class
3912 * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3915 mono_get_delegate_begin_invoke (MonoClass *klass)
3917 MONO_REQ_GC_NEUTRAL_MODE;
3921 /* This is called at runtime, so avoid the slower search in metadata */
3922 mono_class_setup_methods (klass);
3923 if (mono_class_has_failure (klass))
3925 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3930 * mono_get_delegate_end_invoke:
3931 * @klass: The delegate class
3933 * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3936 mono_get_delegate_end_invoke (MonoClass *klass)
3938 MONO_REQ_GC_NEUTRAL_MODE;
3942 /* This is called at runtime, so avoid the slower search in metadata */
3943 mono_class_setup_methods (klass);
3944 if (mono_class_has_failure (klass))
3946 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3951 * mono_runtime_delegate_invoke:
3952 * @delegate: pointer to a delegate object.
3953 * @params: parameters for the delegate.
3954 * @exc: Pointer to the exception result.
3956 * Invokes the delegate method @delegate with the parameters provided.
3958 * You can pass NULL as the exc argument if you don't want to
3959 * catch exceptions, otherwise, *exc will be set to the exception
3960 * thrown, if any. if an exception is thrown, you can't use the
3961 * MonoObject* result from the function.
3964 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3966 MONO_REQ_GC_UNSAFE_MODE;
3970 MonoObject *result = mono_runtime_delegate_try_invoke (delegate, params, exc, &error);
3972 mono_error_cleanup (&error);
3975 if (!is_ok (&error))
3976 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
3980 MonoObject *result = mono_runtime_delegate_invoke_checked (delegate, params, &error);
3981 mono_error_raise_exception (&error); /* FIXME don't raise here */
3987 * mono_runtime_delegate_try_invoke:
3988 * @delegate: pointer to a delegate object.
3989 * @params: parameters for the delegate.
3990 * @exc: Pointer to the exception result.
3991 * @error: set on error
3993 * Invokes the delegate method @delegate with the parameters provided.
3995 * You can pass NULL as the exc argument if you don't want to
3996 * catch exceptions, otherwise, *exc will be set to the exception
3997 * thrown, if any. On failure to execute, @error will be set.
3998 * if an exception is thrown, you can't use the
3999 * MonoObject* result from the function.
4002 mono_runtime_delegate_try_invoke (MonoObject *delegate, void **params, MonoObject **exc, MonoError *error)
4004 MONO_REQ_GC_UNSAFE_MODE;
4006 mono_error_init (error);
4008 MonoClass *klass = delegate->vtable->klass;
4011 im = mono_get_delegate_invoke (klass);
4013 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
4016 o = mono_runtime_try_invoke (im, delegate, params, exc, error);
4018 o = mono_runtime_invoke_checked (im, delegate, params, error);
4025 * mono_runtime_delegate_invoke_checked:
4026 * @delegate: pointer to a delegate object.
4027 * @params: parameters for the delegate.
4028 * @error: set on error
4030 * Invokes the delegate method @delegate with the parameters provided.
4032 * On failure @error will be set and you can't use the MonoObject*
4033 * result from the function.
4036 mono_runtime_delegate_invoke_checked (MonoObject *delegate, void **params, MonoError *error)
4038 mono_error_init (error);
4039 return mono_runtime_delegate_try_invoke (delegate, params, NULL, error);
4042 static char **main_args = NULL;
4043 static int num_main_args = 0;
4046 * mono_runtime_get_main_args:
4048 * Returns: a MonoArray with the arguments passed to the main program
4051 mono_runtime_get_main_args (void)
4053 MONO_REQ_GC_UNSAFE_MODE;
4055 MonoArray *result = mono_runtime_get_main_args_checked (&error);
4056 mono_error_assert_ok (&error);
4061 * mono_runtime_get_main_args:
4062 * @error: set on error
4064 * Returns: a MonoArray with the arguments passed to the main
4065 * program. On failure returns NULL and sets @error.
4068 mono_runtime_get_main_args_checked (MonoError *error)
4072 MonoDomain *domain = mono_domain_get ();
4074 mono_error_init (error);
4076 res = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, num_main_args, error);
4077 return_val_if_nok (error, NULL);
4079 for (i = 0; i < num_main_args; ++i)
4080 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
4086 free_main_args (void)
4088 MONO_REQ_GC_NEUTRAL_MODE;
4092 for (i = 0; i < num_main_args; ++i)
4093 g_free (main_args [i]);
4100 * mono_runtime_set_main_args:
4101 * @argc: number of arguments from the command line
4102 * @argv: array of strings from the command line
4104 * Set the command line arguments from an embedding application that doesn't otherwise call
4105 * mono_runtime_run_main ().
4108 mono_runtime_set_main_args (int argc, char* argv[])
4110 MONO_REQ_GC_NEUTRAL_MODE;
4115 main_args = g_new0 (char*, argc);
4116 num_main_args = argc;
4118 for (i = 0; i < argc; ++i) {
4121 utf8_arg = mono_utf8_from_external (argv[i]);
4122 if (utf8_arg == NULL) {
4123 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
4124 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4128 main_args [i] = utf8_arg;
4135 * mono_runtime_run_main:
4136 * @method: the method to start the application with (usually Main)
4137 * @argc: number of arguments from the command line
4138 * @argv: array of strings from the command line
4139 * @exc: excetption results
4141 * Execute a standard Main() method (argc/argv contains the
4142 * executable name). This method also sets the command line argument value
4143 * needed by System.Environment.
4148 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
4151 MONO_REQ_GC_UNSAFE_MODE;
4155 MonoArray *args = NULL;
4156 MonoDomain *domain = mono_domain_get ();
4157 gchar *utf8_fullpath;
4158 MonoMethodSignature *sig;
4160 g_assert (method != NULL);
4162 mono_thread_set_main (mono_thread_current ());
4164 main_args = g_new0 (char*, argc);
4165 num_main_args = argc;
4167 if (!g_path_is_absolute (argv [0])) {
4168 gchar *basename = g_path_get_basename (argv [0]);
4169 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
4173 utf8_fullpath = mono_utf8_from_external (fullpath);
4174 if(utf8_fullpath == NULL) {
4175 /* Printing the arg text will cause glib to
4176 * whinge about "Invalid UTF-8", but at least
4177 * its relevant, and shows the problem text
4180 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
4181 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4188 utf8_fullpath = mono_utf8_from_external (argv[0]);
4189 if(utf8_fullpath == NULL) {
4190 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
4191 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4196 main_args [0] = utf8_fullpath;
4198 for (i = 1; i < argc; ++i) {
4201 utf8_arg=mono_utf8_from_external (argv[i]);
4202 if(utf8_arg==NULL) {
4203 /* Ditto the comment about Invalid UTF-8 here */
4204 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
4205 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4209 main_args [i] = utf8_arg;
4214 sig = mono_method_signature (method);
4216 g_print ("Unable to load Main method.\n");
4220 if (sig->param_count) {
4221 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, argc, &error);
4222 mono_error_assert_ok (&error);
4223 for (i = 0; i < argc; ++i) {
4224 /* The encodings should all work, given that
4225 * we've checked all these args for the
4228 gchar *str = mono_utf8_from_external (argv [i]);
4229 MonoString *arg = mono_string_new (domain, str);
4230 mono_array_setref (args, i, arg);
4234 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, 0, &error);
4235 mono_error_assert_ok (&error);
4238 mono_assembly_set_main (method->klass->image->assembly);
4240 return mono_runtime_exec_main (method, args, exc);
4244 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4246 static MonoMethod *serialize_method;
4252 if (!serialize_method) {
4253 MonoClass *klass = mono_class_get_remoting_services_class ();
4254 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
4257 if (!serialize_method) {
4262 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
4267 array = mono_runtime_try_invoke (serialize_method, NULL, params, exc, &error);
4268 if (*exc == NULL && !mono_error_ok (&error))
4269 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert serialize_object to MonoError */
4271 mono_error_cleanup (&error);
4280 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4282 MONO_REQ_GC_UNSAFE_MODE;
4284 static MonoMethod *deserialize_method;
4290 if (!deserialize_method) {
4291 MonoClass *klass = mono_class_get_remoting_services_class ();
4292 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
4294 if (!deserialize_method) {
4302 result = mono_runtime_try_invoke (deserialize_method, NULL, params, exc, &error);
4303 if (*exc == NULL && !mono_error_ok (&error))
4304 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert deserialize_object to MonoError */
4306 mono_error_cleanup (&error);
4314 #ifndef DISABLE_REMOTING
4316 make_transparent_proxy (MonoObject *obj, MonoError *error)
4318 MONO_REQ_GC_UNSAFE_MODE;
4320 static MonoMethod *get_proxy_method;
4322 MonoDomain *domain = mono_domain_get ();
4323 MonoRealProxy *real_proxy;
4324 MonoReflectionType *reflection_type;
4325 MonoTransparentProxy *transparent_proxy;
4327 mono_error_init (error);
4329 if (!get_proxy_method)
4330 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
4332 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
4334 real_proxy = (MonoRealProxy*) mono_object_new_checked (domain, mono_defaults.real_proxy_class, error);
4335 return_val_if_nok (error, NULL);
4336 reflection_type = mono_type_get_object_checked (domain, &obj->vtable->klass->byval_arg, error);
4337 return_val_if_nok (error, NULL);
4339 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
4340 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
4342 MonoObject *exc = NULL;
4344 transparent_proxy = (MonoTransparentProxy*) mono_runtime_try_invoke (get_proxy_method, real_proxy, NULL, &exc, error);
4345 if (exc != NULL && is_ok (error))
4346 mono_error_set_exception_instance (error, (MonoException*)exc);
4348 return (MonoObject*) transparent_proxy;
4350 #endif /* DISABLE_REMOTING */
4353 * mono_object_xdomain_representation
4355 * @target_domain: a domain
4356 * @error: set on error.
4358 * Creates a representation of obj in the domain target_domain. This
4359 * is either a copy of obj arrived through via serialization and
4360 * deserialization or a proxy, depending on whether the object is
4361 * serializable or marshal by ref. obj must not be in target_domain.
4363 * If the object cannot be represented in target_domain, NULL is
4364 * returned and @error is set appropriately.
4367 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoError *error)
4369 MONO_REQ_GC_UNSAFE_MODE;
4371 mono_error_init (error);
4372 MonoObject *deserialized = NULL;
4374 #ifndef DISABLE_REMOTING
4375 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
4376 deserialized = make_transparent_proxy (obj, error);
4381 gboolean failure = FALSE;
4382 MonoDomain *domain = mono_domain_get ();
4383 MonoObject *serialized;
4384 MonoObject *exc = NULL;
4386 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
4387 serialized = serialize_object (obj, &failure, &exc);
4388 mono_domain_set_internal_with_options (target_domain, FALSE);
4390 deserialized = deserialize_object (serialized, &failure, &exc);
4391 if (domain != target_domain)
4392 mono_domain_set_internal_with_options (domain, FALSE);
4394 mono_error_set_exception_instance (error, (MonoException*)exc);
4397 return deserialized;
4400 /* Used in call_unhandled_exception_delegate */
4402 create_unhandled_exception_eventargs (MonoObject *exc, MonoError *error)
4404 MONO_REQ_GC_UNSAFE_MODE;
4406 mono_error_init (error);
4409 MonoMethod *method = NULL;
4410 MonoBoolean is_terminating = TRUE;
4413 klass = mono_class_get_unhandled_exception_event_args_class ();
4414 mono_class_init (klass);
4416 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4417 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
4421 args [1] = &is_terminating;
4423 obj = mono_object_new_checked (mono_domain_get (), klass, error);
4424 return_val_if_nok (error, NULL);
4426 mono_runtime_invoke_checked (method, obj, args, error);
4427 return_val_if_nok (error, NULL);
4432 /* Used in mono_unhandled_exception */
4434 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4435 MONO_REQ_GC_UNSAFE_MODE;
4438 MonoObject *e = NULL;
4440 MonoDomain *current_domain = mono_domain_get ();
4442 if (domain != current_domain)
4443 mono_domain_set_internal_with_options (domain, FALSE);
4445 g_assert (domain == mono_object_domain (domain->domain));
4447 if (mono_object_domain (exc) != domain) {
4449 exc = mono_object_xdomain_representation (exc, domain, &error);
4451 if (!is_ok (&error)) {
4452 MonoError inner_error;
4453 MonoException *serialization_exc = mono_error_convert_to_exception (&error);
4454 exc = mono_object_xdomain_representation ((MonoObject*)serialization_exc, domain, &inner_error);
4455 mono_error_assert_ok (&inner_error);
4457 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4458 "System.Runtime.Serialization", "SerializationException",
4459 "Could not serialize unhandled exception.");
4463 g_assert (mono_object_domain (exc) == domain);
4465 pa [0] = domain->domain;
4466 pa [1] = create_unhandled_exception_eventargs (exc, &error);
4467 mono_error_assert_ok (&error);
4468 mono_runtime_delegate_try_invoke (delegate, pa, &e, &error);
4469 if (!is_ok (&error)) {
4471 e = (MonoObject*)mono_error_convert_to_exception (&error);
4473 mono_error_cleanup (&error);
4476 if (domain != current_domain)
4477 mono_domain_set_internal_with_options (current_domain, FALSE);
4480 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4481 if (!mono_error_ok (&error)) {
4482 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4483 mono_error_cleanup (&error);
4485 g_warning ("exception inside UnhandledException handler: %s\n", msg);
4491 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4494 * mono_runtime_unhandled_exception_policy_set:
4495 * @policy: the new policy
4497 * This is a VM internal routine.
4499 * Sets the runtime policy for handling unhandled exceptions.
4502 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4503 runtime_unhandled_exception_policy = policy;
4507 * mono_runtime_unhandled_exception_policy_get:
4509 * This is a VM internal routine.
4511 * Gets the runtime policy for handling unhandled exceptions.
4513 MonoRuntimeUnhandledExceptionPolicy
4514 mono_runtime_unhandled_exception_policy_get (void) {
4515 return runtime_unhandled_exception_policy;
4519 * mono_unhandled_exception:
4520 * @exc: exception thrown
4522 * This is a VM internal routine.
4524 * We call this function when we detect an unhandled exception
4525 * in the default domain.
4527 * It invokes the * UnhandledException event in AppDomain or prints
4528 * a warning to the console
4531 mono_unhandled_exception (MonoObject *exc)
4533 MONO_REQ_GC_UNSAFE_MODE;
4536 MonoClassField *field;
4537 MonoDomain *current_domain, *root_domain;
4538 MonoObject *current_appdomain_delegate = NULL, *root_appdomain_delegate = NULL;
4540 if (mono_class_has_parent (exc->vtable->klass, mono_defaults.threadabortexception_class))
4543 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4546 current_domain = mono_domain_get ();
4547 root_domain = mono_get_root_domain ();
4549 root_appdomain_delegate = mono_field_get_value_object_checked (root_domain, field, (MonoObject*) root_domain->domain, &error);
4550 mono_error_assert_ok (&error);
4551 if (current_domain != root_domain) {
4552 current_appdomain_delegate = mono_field_get_value_object_checked (current_domain, field, (MonoObject*) current_domain->domain, &error);
4553 mono_error_assert_ok (&error);
4556 if (!current_appdomain_delegate && !root_appdomain_delegate) {
4557 mono_print_unhandled_exception (exc);
4559 if (root_appdomain_delegate)
4560 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4561 if (current_appdomain_delegate)
4562 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4565 /* set exitcode only if we will abort the process */
4566 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4567 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4569 mono_environment_exitcode_set (1);
4574 * mono_runtime_exec_managed_code:
4575 * @domain: Application domain
4576 * @main_func: function to invoke from the execution thread
4577 * @main_args: parameter to the main_func
4579 * Launch a new thread to execute a function
4581 * main_func is called back from the thread with main_args as the
4582 * parameter. The callback function is expected to start Main()
4583 * eventually. This function then waits for all managed threads to
4585 * It is not necesseray anymore to execute managed code in a subthread,
4586 * so this function should not be used anymore by default: just
4587 * execute the code and then call mono_thread_manage ().
4590 mono_runtime_exec_managed_code (MonoDomain *domain,
4591 MonoMainThreadFunc main_func,
4595 mono_thread_create_checked (domain, main_func, main_args, &error);
4596 mono_error_assert_ok (&error);
4598 mono_thread_manage ();
4602 * Execute a standard Main() method (args doesn't contain the
4606 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4608 MONO_REQ_GC_UNSAFE_MODE;
4614 MonoCustomAttrInfo* cinfo;
4615 gboolean has_stathread_attribute;
4616 MonoInternalThread* thread = mono_thread_internal_current ();
4622 domain = mono_object_domain (args);
4623 if (!domain->entry_assembly) {
4625 MonoAssembly *assembly;
4627 assembly = method->klass->image->assembly;
4628 domain->entry_assembly = assembly;
4629 /* Domains created from another domain already have application_base and configuration_file set */
4630 if (domain->setup->application_base == NULL) {
4631 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4634 if (domain->setup->configuration_file == NULL) {
4635 str = g_strconcat (assembly->image->name, ".config", NULL);
4636 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4638 mono_domain_set_options_from_config (domain);
4642 cinfo = mono_custom_attrs_from_method_checked (method, &error);
4643 mono_error_cleanup (&error); /* FIXME warn here? */
4645 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, mono_class_get_sta_thread_attribute_class ());
4647 mono_custom_attrs_free (cinfo);
4649 has_stathread_attribute = FALSE;
4651 if (has_stathread_attribute) {
4652 thread->apartment_state = ThreadApartmentState_STA;
4654 thread->apartment_state = ThreadApartmentState_MTA;
4656 mono_thread_init_apartment_state ();
4658 /* FIXME: check signature of method */
4659 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4662 res = mono_runtime_try_invoke (method, NULL, pa, exc, &error);
4663 if (*exc == NULL && !mono_error_ok (&error))
4664 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4666 mono_error_cleanup (&error);
4668 res = mono_runtime_invoke_checked (method, NULL, pa, &error);
4669 mono_error_raise_exception (&error); /* FIXME don't raise here */
4673 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4677 mono_environment_exitcode_set (rval);
4680 mono_runtime_try_invoke (method, NULL, pa, exc, &error);
4681 if (*exc == NULL && !mono_error_ok (&error))
4682 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4684 mono_error_cleanup (&error);
4686 mono_runtime_invoke_checked (method, NULL, pa, &error);
4687 mono_error_raise_exception (&error); /* FIXME don't raise here */
4693 /* If the return type of Main is void, only
4694 * set the exitcode if an exception was thrown
4695 * (we don't want to blow away an
4696 * explicitly-set exit code)
4699 mono_environment_exitcode_set (rval);
4706 /** invoke_array_extract_argument:
4707 * @params: array of arguments to the method.
4708 * @i: the index of the argument to extract.
4709 * @t: ith type from the method signature.
4710 * @has_byref_nullables: outarg - TRUE if method expects a byref nullable argument
4711 * @error: set on error.
4713 * Given an array of method arguments, return the ith one using the corresponding type
4714 * to perform necessary unboxing. If method expects a ref nullable argument, writes TRUE to @has_byref_nullables.
4716 * On failure sets @error and returns NULL.
4719 invoke_array_extract_argument (MonoArray *params, int i, MonoType *t, gboolean* has_byref_nullables, MonoError *error)
4721 MonoType *t_orig = t;
4722 gpointer result = NULL;
4723 mono_error_init (error);
4728 case MONO_TYPE_BOOLEAN:
4731 case MONO_TYPE_CHAR:
4740 case MONO_TYPE_VALUETYPE:
4741 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (t_orig))) {
4742 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4743 result = mono_array_get (params, MonoObject*, i);
4745 *has_byref_nullables = TRUE;
4747 /* MS seems to create the objects if a null is passed in */
4748 if (!mono_array_get (params, MonoObject*, i)) {
4749 MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (t_orig), error);
4750 return_val_if_nok (error, NULL);
4751 mono_array_setref (params, i, o);
4756 * We can't pass the unboxed vtype byref to the callee, since
4757 * that would mean the callee would be able to modify boxed
4758 * primitive types. So we (and MS) make a copy of the boxed
4759 * object, pass that to the callee, and replace the original
4760 * boxed object in the arg array with the copy.
4762 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4763 MonoObject *copy = mono_value_box_checked (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig), error);
4764 return_val_if_nok (error, NULL);
4765 mono_array_setref (params, i, copy);
4768 result = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4771 case MONO_TYPE_STRING:
4772 case MONO_TYPE_OBJECT:
4773 case MONO_TYPE_CLASS:
4774 case MONO_TYPE_ARRAY:
4775 case MONO_TYPE_SZARRAY:
4777 result = mono_array_addr (params, MonoObject*, i);
4778 // FIXME: I need to check this code path
4780 result = mono_array_get (params, MonoObject*, i);
4782 case MONO_TYPE_GENERICINST:
4784 t = &t->data.generic_class->container_class->this_arg;
4786 t = &t->data.generic_class->container_class->byval_arg;
4788 case MONO_TYPE_PTR: {
4791 /* The argument should be an IntPtr */
4792 arg = mono_array_get (params, MonoObject*, i);
4796 g_assert (arg->vtable->klass == mono_defaults.int_class);
4797 result = ((MonoIntPtr*)arg)->m_value;
4802 g_error ("type 0x%x not handled in mono_runtime_invoke_array", t_orig->type);
4807 * mono_runtime_invoke_array:
4808 * @method: method to invoke
4809 * @obJ: object instance
4810 * @params: arguments to the method
4811 * @exc: exception information.
4813 * Invokes the method represented by @method on the object @obj.
4815 * obj is the 'this' pointer, it should be NULL for static
4816 * methods, a MonoObject* for object instances and a pointer to
4817 * the value type for value types.
4819 * The params array contains the arguments to the method with the
4820 * same convention: MonoObject* pointers for object instances and
4821 * pointers to the value type otherwise. The _invoke_array
4822 * variant takes a C# object[] as the params argument (MonoArray
4823 * *params): in this case the value types are boxed inside the
4824 * respective reference representation.
4826 * From unmanaged code you'll usually use the
4827 * mono_runtime_invoke_checked() variant.
4829 * Note that this function doesn't handle virtual methods for
4830 * you, it will exec the exact method you pass: we still need to
4831 * expose a function to lookup the derived class implementation
4832 * of a virtual method (there are examples of this in the code,
4835 * You can pass NULL as the exc argument if you don't want to
4836 * catch exceptions, otherwise, *exc will be set to the exception
4837 * thrown, if any. if an exception is thrown, you can't use the
4838 * MonoObject* result from the function.
4840 * If the method returns a value type, it is boxed in an object
4844 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4849 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, exc, &error);
4851 mono_error_cleanup (&error);
4854 if (!is_ok (&error))
4855 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
4859 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, NULL, &error);
4860 mono_error_raise_exception (&error); /* FIXME don't raise here */
4866 * mono_runtime_invoke_array_checked:
4867 * @method: method to invoke
4868 * @obJ: object instance
4869 * @params: arguments to the method
4870 * @error: set on failure.
4872 * Invokes the method represented by @method on the object @obj.
4874 * obj is the 'this' pointer, it should be NULL for static
4875 * methods, a MonoObject* for object instances and a pointer to
4876 * the value type for value types.
4878 * The params array contains the arguments to the method with the
4879 * same convention: MonoObject* pointers for object instances and
4880 * pointers to the value type otherwise. The _invoke_array
4881 * variant takes a C# object[] as the params argument (MonoArray
4882 * *params): in this case the value types are boxed inside the
4883 * respective reference representation.
4885 * From unmanaged code you'll usually use the
4886 * mono_runtime_invoke_checked() variant.
4888 * Note that this function doesn't handle virtual methods for
4889 * you, it will exec the exact method you pass: we still need to
4890 * expose a function to lookup the derived class implementation
4891 * of a virtual method (there are examples of this in the code,
4894 * On failure or exception, @error will be set. In that case, you
4895 * can't use the MonoObject* result from the function.
4897 * If the method returns a value type, it is boxed in an object
4901 mono_runtime_invoke_array_checked (MonoMethod *method, void *obj, MonoArray *params,
4904 mono_error_init (error);
4905 return mono_runtime_try_invoke_array (method, obj, params, NULL, error);
4909 * mono_runtime_try_invoke_array:
4910 * @method: method to invoke
4911 * @obJ: object instance
4912 * @params: arguments to the method
4913 * @exc: exception information.
4914 * @error: set on failure.
4916 * Invokes the method represented by @method on the object @obj.
4918 * obj is the 'this' pointer, it should be NULL for static
4919 * methods, a MonoObject* for object instances and a pointer to
4920 * the value type for value types.
4922 * The params array contains the arguments to the method with the
4923 * same convention: MonoObject* pointers for object instances and
4924 * pointers to the value type otherwise. The _invoke_array
4925 * variant takes a C# object[] as the params argument (MonoArray
4926 * *params): in this case the value types are boxed inside the
4927 * respective reference representation.
4929 * From unmanaged code you'll usually use the
4930 * mono_runtime_invoke_checked() variant.
4932 * Note that this function doesn't handle virtual methods for
4933 * you, it will exec the exact method you pass: we still need to
4934 * expose a function to lookup the derived class implementation
4935 * of a virtual method (there are examples of this in the code,
4938 * You can pass NULL as the exc argument if you don't want to catch
4939 * exceptions, otherwise, *exc will be set to the exception thrown, if
4940 * any. On other failures, @error will be set. If an exception is
4941 * thrown or there's an error, you can't use the MonoObject* result
4942 * from the function.
4944 * If the method returns a value type, it is boxed in an object
4948 mono_runtime_try_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4949 MonoObject **exc, MonoError *error)
4951 MONO_REQ_GC_UNSAFE_MODE;
4953 mono_error_init (error);
4955 MonoMethodSignature *sig = mono_method_signature (method);
4956 gpointer *pa = NULL;
4959 gboolean has_byref_nullables = FALSE;
4961 if (NULL != params) {
4962 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
4963 for (i = 0; i < mono_array_length (params); i++) {
4964 MonoType *t = sig->params [i];
4965 pa [i] = invoke_array_extract_argument (params, i, t, &has_byref_nullables, error);
4966 return_val_if_nok (error, NULL);
4970 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4973 if (mono_class_is_nullable (method->klass)) {
4974 /* Need to create a boxed vtype instead */
4980 return mono_value_box_checked (mono_domain_get (), method->klass->cast_class, pa [0], error);
4985 obj = mono_object_new_checked (mono_domain_get (), method->klass, error);
4986 mono_error_assert_ok (error);
4987 g_assert (obj); /*maybe we should raise a TLE instead?*/
4988 #ifndef DISABLE_REMOTING
4989 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
4990 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
4993 if (method->klass->valuetype)
4994 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
4997 } else if (method->klass->valuetype) {
4998 obj = mono_value_box_checked (mono_domain_get (), method->klass, obj, error);
4999 return_val_if_nok (error, NULL);
5003 mono_runtime_try_invoke (method, o, pa, exc, error);
5005 mono_runtime_invoke_checked (method, o, pa, error);
5008 return (MonoObject *)obj;
5010 if (mono_class_is_nullable (method->klass)) {
5011 MonoObject *nullable;
5013 /* Convert the unboxed vtype into a Nullable structure */
5014 nullable = mono_object_new_checked (mono_domain_get (), method->klass, error);
5015 return_val_if_nok (error, NULL);
5017 MonoObject *boxed = mono_value_box_checked (mono_domain_get (), method->klass->cast_class, obj, error);
5018 return_val_if_nok (error, NULL);
5019 mono_nullable_init ((guint8 *)mono_object_unbox (nullable), boxed, method->klass);
5020 obj = mono_object_unbox (nullable);
5023 /* obj must be already unboxed if needed */
5025 res = mono_runtime_try_invoke (method, obj, pa, exc, error);
5027 res = mono_runtime_invoke_checked (method, obj, pa, error);
5029 return_val_if_nok (error, NULL);
5031 if (sig->ret->type == MONO_TYPE_PTR) {
5032 MonoClass *pointer_class;
5033 static MonoMethod *box_method;
5035 MonoObject *box_exc;
5038 * The runtime-invoke wrapper returns a boxed IntPtr, need to
5039 * convert it to a Pointer object.
5041 pointer_class = mono_class_get_pointer_class ();
5043 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
5045 g_assert (res->vtable->klass == mono_defaults.int_class);
5046 box_args [0] = ((MonoIntPtr*)res)->m_value;
5047 box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, error);
5048 return_val_if_nok (error, NULL);
5050 res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, error);
5051 g_assert (box_exc == NULL);
5052 mono_error_assert_ok (error);
5055 if (has_byref_nullables) {
5057 * The runtime invoke wrapper already converted byref nullables back,
5058 * and stored them in pa, we just need to copy them back to the
5061 for (i = 0; i < mono_array_length (params); i++) {
5062 MonoType *t = sig->params [i];
5064 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
5065 mono_array_setref (params, i, pa [i]);
5075 * @klass: the class of the object that we want to create
5077 * Returns: a newly created object whose definition is
5078 * looked up using @klass. This will not invoke any constructors,
5079 * so the consumer of this routine has to invoke any constructors on
5080 * its own to initialize the object.
5082 * It returns NULL on failure.
5085 mono_object_new (MonoDomain *domain, MonoClass *klass)
5087 MONO_REQ_GC_UNSAFE_MODE;
5091 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5093 mono_error_cleanup (&error);
5098 ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
5100 MONO_REQ_GC_UNSAFE_MODE;
5104 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5106 mono_error_set_pending_exception (&error);
5111 * mono_object_new_checked:
5112 * @klass: the class of the object that we want to create
5113 * @error: set on error
5115 * Returns: a newly created object whose definition is
5116 * looked up using @klass. This will not invoke any constructors,
5117 * so the consumer of this routine has to invoke any constructors on
5118 * its own to initialize the object.
5120 * It returns NULL on failure and sets @error.
5123 mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
5125 MONO_REQ_GC_UNSAFE_MODE;
5129 vtable = mono_class_vtable (domain, klass);
5130 g_assert (vtable); /* FIXME don't swallow the error */
5132 MonoObject *o = mono_object_new_specific_checked (vtable, error);
5137 * mono_object_new_pinned:
5139 * Same as mono_object_new, but the returned object will be pinned.
5140 * For SGEN, these objects will only be freed at appdomain unload.
5143 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
5145 MONO_REQ_GC_UNSAFE_MODE;
5149 mono_error_init (error);
5151 vtable = mono_class_vtable (domain, klass);
5152 g_assert (vtable); /* FIXME don't swallow the error */
5154 MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
5156 if (G_UNLIKELY (!o))
5157 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
5158 else if (G_UNLIKELY (vtable->klass->has_finalize))
5159 mono_object_register_finalizer (o, error);
5165 * mono_object_new_specific:
5166 * @vtable: the vtable of the object that we want to create
5168 * Returns: A newly created object with class and domain specified
5172 mono_object_new_specific (MonoVTable *vtable)
5175 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5176 mono_error_cleanup (&error);
5182 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
5184 MONO_REQ_GC_UNSAFE_MODE;
5188 mono_error_init (error);
5190 /* check for is_com_object for COM Interop */
5191 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
5194 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
5197 MonoClass *klass = mono_class_get_activation_services_class ();
5200 mono_class_init (klass);
5202 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
5204 mono_error_set_not_supported (error, "Linked away.");
5207 vtable->domain->create_proxy_for_type_method = im;
5210 pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
5211 if (!mono_error_ok (error))
5214 o = mono_runtime_invoke_checked (im, NULL, pa, error);
5215 if (!mono_error_ok (error))
5222 return mono_object_new_alloc_specific_checked (vtable, error);
5226 ves_icall_object_new_specific (MonoVTable *vtable)
5229 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5230 mono_error_set_pending_exception (&error);
5236 * mono_object_new_alloc_specific:
5237 * @vtable: virtual table for the object.
5239 * This function allocates a new `MonoObject` with the type derived
5240 * from the @vtable information. If the class of this object has a
5241 * finalizer, then the object will be tracked for finalization.
5243 * This method might raise an exception on errors. Use the
5244 * `mono_object_new_fast_checked` method if you want to manually raise
5247 * Returns: the allocated object.
5250 mono_object_new_alloc_specific (MonoVTable *vtable)
5253 MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
5254 mono_error_cleanup (&error);
5260 * mono_object_new_alloc_specific_checked:
5261 * @vtable: virtual table for the object.
5262 * @error: holds the error return value.
5264 * This function allocates a new `MonoObject` with the type derived
5265 * from the @vtable information. If the class of this object has a
5266 * finalizer, then the object will be tracked for finalization.
5268 * If there is not enough memory, the @error parameter will be set
5269 * and will contain a user-visible message with the amount of bytes
5270 * that were requested.
5272 * Returns: the allocated object, or NULL if there is not enough memory
5276 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
5278 MONO_REQ_GC_UNSAFE_MODE;
5282 mono_error_init (error);
5284 o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5286 if (G_UNLIKELY (!o))
5287 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5288 else if (G_UNLIKELY (vtable->klass->has_finalize))
5289 mono_object_register_finalizer (o, error);
5295 * mono_object_new_fast:
5296 * @vtable: virtual table for the object.
5298 * This function allocates a new `MonoObject` with the type derived
5299 * from the @vtable information. The returned object is not tracked
5300 * for finalization. If your object implements a finalizer, you should
5301 * use `mono_object_new_alloc_specific` instead.
5303 * This method might raise an exception on errors. Use the
5304 * `mono_object_new_fast_checked` method if you want to manually raise
5307 * Returns: the allocated object.
5310 mono_object_new_fast (MonoVTable *vtable)
5313 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5314 mono_error_cleanup (&error);
5320 * mono_object_new_fast_checked:
5321 * @vtable: virtual table for the object.
5322 * @error: holds the error return value.
5324 * This function allocates a new `MonoObject` with the type derived
5325 * from the @vtable information. The returned object is not tracked
5326 * for finalization. If your object implements a finalizer, you should
5327 * use `mono_object_new_alloc_specific_checked` instead.
5329 * If there is not enough memory, the @error parameter will be set
5330 * and will contain a user-visible message with the amount of bytes
5331 * that were requested.
5333 * Returns: the allocated object, or NULL if there is not enough memory
5337 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
5339 MONO_REQ_GC_UNSAFE_MODE;
5343 mono_error_init (error);
5345 o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5347 if (G_UNLIKELY (!o))
5348 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5354 ves_icall_object_new_fast (MonoVTable *vtable)
5357 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5358 mono_error_set_pending_exception (&error);
5364 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
5366 MONO_REQ_GC_UNSAFE_MODE;
5370 mono_error_init (error);
5372 o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
5374 if (G_UNLIKELY (!o))
5375 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5376 else if (G_UNLIKELY (vtable->klass->has_finalize))
5377 mono_object_register_finalizer (o, error);
5383 * mono_class_get_allocation_ftn:
5385 * @for_box: the object will be used for boxing
5386 * @pass_size_in_words:
5388 * Return the allocation function appropriate for the given class.
5392 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
5394 MONO_REQ_GC_NEUTRAL_MODE;
5396 *pass_size_in_words = FALSE;
5398 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass) || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
5399 return ves_icall_object_new_specific;
5401 if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
5403 return ves_icall_object_new_fast;
5406 * FIXME: This is actually slower than ves_icall_object_new_fast, because
5407 * of the overhead of parameter passing.
5410 *pass_size_in_words = TRUE;
5411 #ifdef GC_REDIRECT_TO_LOCAL
5412 return GC_local_gcj_fast_malloc;
5414 return GC_gcj_fast_malloc;
5419 return ves_icall_object_new_specific;
5423 * mono_object_new_from_token:
5424 * @image: Context where the type_token is hosted
5425 * @token: a token of the type that we want to create
5427 * Returns: A newly created object whose definition is
5428 * looked up using @token in the @image image
5431 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
5433 MONO_REQ_GC_UNSAFE_MODE;
5439 klass = mono_class_get_checked (image, token, &error);
5440 mono_error_assert_ok (&error);
5442 result = mono_object_new_checked (domain, klass, &error);
5444 mono_error_cleanup (&error);
5451 * mono_object_clone:
5452 * @obj: the object to clone
5454 * Returns: A newly created object who is a shallow copy of @obj
5457 mono_object_clone (MonoObject *obj)
5460 MonoObject *o = mono_object_clone_checked (obj, &error);
5461 mono_error_cleanup (&error);
5467 mono_object_clone_checked (MonoObject *obj, MonoError *error)
5469 MONO_REQ_GC_UNSAFE_MODE;
5474 mono_error_init (error);
5476 size = obj->vtable->klass->instance_size;
5478 if (obj->vtable->klass->rank)
5479 return (MonoObject*)mono_array_clone_checked ((MonoArray*)obj, error);
5481 o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
5483 if (G_UNLIKELY (!o)) {
5484 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5488 /* If the object doesn't contain references this will do a simple memmove. */
5489 mono_gc_wbarrier_object_copy (o, obj);
5491 if (obj->vtable->klass->has_finalize)
5492 mono_object_register_finalizer (o, error);
5497 * mono_array_full_copy:
5498 * @src: source array to copy
5499 * @dest: destination array
5501 * Copies the content of one array to another with exactly the same type and size.
5504 mono_array_full_copy (MonoArray *src, MonoArray *dest)
5506 MONO_REQ_GC_UNSAFE_MODE;
5509 MonoClass *klass = src->obj.vtable->klass;
5511 g_assert (klass == dest->obj.vtable->klass);
5513 size = mono_array_length (src);
5514 g_assert (size == mono_array_length (dest));
5515 size *= mono_array_element_size (klass);
5517 if (klass->element_class->valuetype) {
5518 if (klass->element_class->has_references)
5519 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
5521 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5523 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
5526 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5531 * mono_array_clone_in_domain:
5532 * @domain: the domain in which the array will be cloned into
5533 * @array: the array to clone
5534 * @error: set on error
5536 * This routine returns a copy of the array that is hosted on the
5537 * specified MonoDomain. On failure returns NULL and sets @error.
5540 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array, MonoError *error)
5542 MONO_REQ_GC_UNSAFE_MODE;
5547 MonoClass *klass = array->obj.vtable->klass;
5549 mono_error_init (error);
5551 if (array->bounds == NULL) {
5552 size = mono_array_length (array);
5553 o = mono_array_new_full_checked (domain, klass, &size, NULL, error);
5554 return_val_if_nok (error, NULL);
5556 size *= mono_array_element_size (klass);
5558 if (klass->element_class->valuetype) {
5559 if (klass->element_class->has_references)
5560 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5562 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5564 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5567 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5572 sizes = (uintptr_t *)alloca (klass->rank * sizeof(intptr_t) * 2);
5573 size = mono_array_element_size (klass);
5574 for (i = 0; i < klass->rank; ++i) {
5575 sizes [i] = array->bounds [i].length;
5576 size *= array->bounds [i].length;
5577 sizes [i + klass->rank] = array->bounds [i].lower_bound;
5579 o = mono_array_new_full_checked (domain, klass, sizes, (intptr_t*)sizes + klass->rank, error);
5580 return_val_if_nok (error, NULL);
5582 if (klass->element_class->valuetype) {
5583 if (klass->element_class->has_references)
5584 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5586 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5588 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5591 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5599 * @array: the array to clone
5601 * Returns: A newly created array who is a shallow copy of @array
5604 mono_array_clone (MonoArray *array)
5606 MONO_REQ_GC_UNSAFE_MODE;
5609 MonoArray *result = mono_array_clone_checked (array, &error);
5610 mono_error_cleanup (&error);
5615 * mono_array_clone_checked:
5616 * @array: the array to clone
5617 * @error: set on error
5619 * Returns: A newly created array who is a shallow copy of @array. On
5620 * failure returns NULL and sets @error.
5623 mono_array_clone_checked (MonoArray *array, MonoError *error)
5626 MONO_REQ_GC_UNSAFE_MODE;
5627 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array, error);
5630 /* helper macros to check for overflow when calculating the size of arrays */
5631 #ifdef MONO_BIG_ARRAYS
5632 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
5633 #define MYGUINT_MAX MYGUINT64_MAX
5634 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5635 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
5636 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5637 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
5638 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
5640 #define MYGUINT32_MAX 4294967295U
5641 #define MYGUINT_MAX MYGUINT32_MAX
5642 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5643 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
5644 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5645 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
5646 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
5650 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
5652 MONO_REQ_GC_NEUTRAL_MODE;
5656 byte_len = mono_array_element_size (klass);
5657 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
5660 if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
5662 byte_len += MONO_SIZEOF_MONO_ARRAY;
5670 * mono_array_new_full:
5671 * @domain: domain where the object is created
5672 * @array_class: array class
5673 * @lengths: lengths for each dimension in the array
5674 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
5676 * This routine creates a new array objects with the given dimensions,
5677 * lower bounds and type.
5680 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
5683 MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
5684 mono_error_cleanup (&error);
5690 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
5692 MONO_REQ_GC_UNSAFE_MODE;
5694 uintptr_t byte_len = 0, len, bounds_size;
5697 MonoArrayBounds *bounds;
5701 mono_error_init (error);
5703 if (!array_class->inited)
5704 mono_class_init (array_class);
5708 /* A single dimensional array with a 0 lower bound is the same as an szarray */
5709 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
5711 if (len > MONO_ARRAY_MAX_INDEX) {
5712 mono_error_set_generic_error (error, "System", "OverflowException", "");
5717 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
5719 for (i = 0; i < array_class->rank; ++i) {
5720 if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
5721 mono_error_set_generic_error (error, "System", "OverflowException", "");
5724 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5725 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5732 if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5733 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5739 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5740 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5743 byte_len = (byte_len + 3) & ~3;
5744 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5745 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5748 byte_len += bounds_size;
5751 * Following three lines almost taken from mono_object_new ():
5752 * they need to be kept in sync.
5754 vtable = mono_class_vtable_full (domain, array_class, error);
5755 return_val_if_nok (error, NULL);
5758 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5760 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5762 if (G_UNLIKELY (!o)) {
5763 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", byte_len);
5767 array = (MonoArray*)o;
5769 bounds = array->bounds;
5772 for (i = 0; i < array_class->rank; ++i) {
5773 bounds [i].length = lengths [i];
5775 bounds [i].lower_bound = lower_bounds [i];
5784 * @domain: domain where the object is created
5785 * @eclass: element class
5786 * @n: number of array elements
5788 * This routine creates a new szarray with @n elements of type @eclass.
5791 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5793 MONO_REQ_GC_UNSAFE_MODE;
5796 MonoArray *result = mono_array_new_checked (domain, eclass, n, &error);
5797 mono_error_cleanup (&error);
5802 * mono_array_new_checked:
5803 * @domain: domain where the object is created
5804 * @eclass: element class
5805 * @n: number of array elements
5806 * @error: set on error
5808 * This routine creates a new szarray with @n elements of type @eclass.
5809 * On failure returns NULL and sets @error.
5812 mono_array_new_checked (MonoDomain *domain, MonoClass *eclass, uintptr_t n, MonoError *error)
5816 mono_error_init (error);
5818 ac = mono_array_class_get (eclass, 1);
5821 MonoVTable *vtable = mono_class_vtable_full (domain, ac, error);
5822 return_val_if_nok (error, NULL);
5824 return mono_array_new_specific_checked (vtable, n, error);
5828 ves_icall_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5831 MonoArray *arr = mono_array_new_checked (domain, eclass, n, &error);
5832 mono_error_set_pending_exception (&error);
5838 * mono_array_new_specific:
5839 * @vtable: a vtable in the appropriate domain for an initialized class
5840 * @n: number of array elements
5842 * This routine is a fast alternative to mono_array_new() for code which
5843 * can be sure about the domain it operates in.
5846 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5849 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5850 mono_error_cleanup (&error);
5856 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
5858 MONO_REQ_GC_UNSAFE_MODE;
5863 mono_error_init (error);
5865 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
5866 mono_error_set_generic_error (error, "System", "OverflowException", "");
5870 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
5871 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5874 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
5876 if (G_UNLIKELY (!o)) {
5877 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", byte_len);
5881 return (MonoArray*)o;
5885 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
5888 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5889 mono_error_set_pending_exception (&error);
5895 * mono_string_new_utf16:
5896 * @text: a pointer to an utf16 string
5897 * @len: the length of the string
5899 * Returns: A newly created string object which contains @text.
5902 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
5904 MONO_REQ_GC_UNSAFE_MODE;
5907 MonoString *res = NULL;
5908 res = mono_string_new_utf16_checked (domain, text, len, &error);
5909 mono_error_cleanup (&error);
5915 * mono_string_new_utf16_checked:
5916 * @text: a pointer to an utf16 string
5917 * @len: the length of the string
5918 * @error: written on error.
5920 * Returns: A newly created string object which contains @text.
5921 * On error, returns NULL and sets @error.
5924 mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
5926 MONO_REQ_GC_UNSAFE_MODE;
5930 mono_error_init (error);
5932 s = mono_string_new_size_checked (domain, len, error);
5934 memcpy (mono_string_chars (s), text, len * 2);
5940 * mono_string_new_utf32:
5941 * @text: a pointer to an utf32 string
5942 * @len: the length of the string
5943 * @error: set on failure.
5945 * Returns: A newly created string object which contains @text. On failure returns NULL and sets @error.
5948 mono_string_new_utf32_checked (MonoDomain *domain, const mono_unichar4 *text, gint32 len, MonoError *error)
5950 MONO_REQ_GC_UNSAFE_MODE;
5953 mono_unichar2 *utf16_output = NULL;
5954 gint32 utf16_len = 0;
5955 GError *gerror = NULL;
5956 glong items_written;
5958 mono_error_init (error);
5959 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
5962 g_error_free (gerror);
5964 while (utf16_output [utf16_len]) utf16_len++;
5966 s = mono_string_new_size_checked (domain, utf16_len, error);
5967 return_val_if_nok (error, NULL);
5969 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
5971 g_free (utf16_output);
5977 * mono_string_new_utf32:
5978 * @text: a pointer to an utf32 string
5979 * @len: the length of the string
5981 * Returns: A newly created string object which contains @text.
5984 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
5987 MonoString *result = mono_string_new_utf32_checked (domain, text, len, &error);
5988 mono_error_cleanup (&error);
5993 * mono_string_new_size:
5994 * @text: a pointer to an utf16 string
5995 * @len: the length of the string
5997 * Returns: A newly created string object of @len
6000 mono_string_new_size (MonoDomain *domain, gint32 len)
6003 MonoString *str = mono_string_new_size_checked (domain, len, &error);
6004 mono_error_cleanup (&error);
6010 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
6012 MONO_REQ_GC_UNSAFE_MODE;
6018 mono_error_init (error);
6020 /* check for overflow */
6021 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
6022 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
6026 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
6027 g_assert (size > 0);
6029 vtable = mono_class_vtable (domain, mono_defaults.string_class);
6032 s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
6034 if (G_UNLIKELY (!s)) {
6035 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6043 * mono_string_new_len:
6044 * @text: a pointer to an utf8 string
6045 * @length: number of bytes in @text to consider
6047 * Returns: A newly created string object which contains @text.
6050 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
6052 MONO_REQ_GC_UNSAFE_MODE;
6055 MonoString *result = mono_string_new_len_checked (domain, text, length, &error);
6056 mono_error_cleanup (&error);
6061 * mono_string_new_len_checked:
6062 * @text: a pointer to an utf8 string
6063 * @length: number of bytes in @text to consider
6064 * @error: set on error
6066 * Returns: A newly created string object which contains @text. On
6067 * failure returns NULL and sets @error.
6070 mono_string_new_len_checked (MonoDomain *domain, const char *text, guint length, MonoError *error)
6072 MONO_REQ_GC_UNSAFE_MODE;
6074 mono_error_init (error);
6076 GError *eg_error = NULL;
6077 MonoString *o = NULL;
6079 glong items_written;
6081 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
6084 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6086 g_error_free (eg_error);
6095 * @text: a pointer to an utf8 string
6097 * Returns: A newly created string object which contains @text.
6099 * This function asserts if it cannot allocate a new string.
6101 * @deprecated Use mono_string_new_checked in new code.
6104 mono_string_new (MonoDomain *domain, const char *text)
6107 MonoString *res = NULL;
6108 res = mono_string_new_checked (domain, text, &error);
6109 mono_error_assert_ok (&error);
6114 * mono_string_new_checked:
6115 * @text: a pointer to an utf8 string
6116 * @merror: set on error
6118 * Returns: A newly created string object which contains @text.
6119 * On error returns NULL and sets @merror.
6122 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
6124 MONO_REQ_GC_UNSAFE_MODE;
6126 GError *eg_error = NULL;
6127 MonoString *o = NULL;
6129 glong items_written;
6132 mono_error_init (error);
6136 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &eg_error);
6139 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6141 g_error_free (eg_error);
6145 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
6150 MonoString *o = NULL;
6152 if (!g_utf8_validate (text, -1, &end)) {
6153 mono_error_set_argument (error, "text", "Not a valid utf8 string");
6157 len = g_utf8_strlen (text, -1);
6158 o = mono_string_new_size_checked (domain, len, error);
6161 str = mono_string_chars (o);
6163 while (text < end) {
6164 *str++ = g_utf8_get_char (text);
6165 text = g_utf8_next_char (text);
6174 * mono_string_new_wrapper:
6175 * @text: pointer to utf8 characters.
6177 * Helper function to create a string object from @text in the current domain.
6180 mono_string_new_wrapper (const char *text)
6182 MONO_REQ_GC_UNSAFE_MODE;
6184 MonoDomain *domain = mono_domain_get ();
6187 return mono_string_new (domain, text);
6194 * @class: the class of the value
6195 * @value: a pointer to the unboxed data
6197 * Returns: A newly created object which contains @value.
6200 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
6203 MonoObject *result = mono_value_box_checked (domain, klass, value, &error);
6204 mono_error_cleanup (&error);
6209 * mono_value_box_checked:
6210 * @domain: the domain of the new object
6211 * @class: the class of the value
6212 * @value: a pointer to the unboxed data
6213 * @error: set on error
6215 * Returns: A newly created object which contains @value. On failure
6216 * returns NULL and sets @error.
6219 mono_value_box_checked (MonoDomain *domain, MonoClass *klass, gpointer value, MonoError *error)
6221 MONO_REQ_GC_UNSAFE_MODE;
6226 mono_error_init (error);
6228 g_assert (klass->valuetype);
6229 if (mono_class_is_nullable (klass))
6230 return mono_nullable_box ((guint8 *)value, klass, error);
6232 vtable = mono_class_vtable (domain, klass);
6235 size = mono_class_instance_size (klass);
6236 res = mono_object_new_alloc_specific_checked (vtable, error);
6237 return_val_if_nok (error, NULL);
6239 size = size - sizeof (MonoObject);
6242 g_assert (size == mono_class_value_size (klass, NULL));
6243 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
6245 #if NO_UNALIGNED_ACCESS
6246 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6250 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
6253 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
6256 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
6259 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
6262 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6266 if (klass->has_finalize) {
6267 mono_object_register_finalizer (res, error);
6268 return_val_if_nok (error, NULL);
6275 * @dest: destination pointer
6276 * @src: source pointer
6277 * @klass: a valuetype class
6279 * Copy a valuetype from @src to @dest. This function must be used
6280 * when @klass contains references fields.
6283 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
6285 MONO_REQ_GC_UNSAFE_MODE;
6287 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
6291 * mono_value_copy_array:
6292 * @dest: destination array
6293 * @dest_idx: index in the @dest array
6294 * @src: source pointer
6295 * @count: number of items
6297 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
6298 * This function must be used when @klass contains references fields.
6299 * Overlap is handled.
6302 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
6304 MONO_REQ_GC_UNSAFE_MODE;
6306 int size = mono_array_element_size (dest->obj.vtable->klass);
6307 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
6308 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
6309 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
6313 * mono_object_get_domain:
6314 * @obj: object to query
6316 * Returns: the MonoDomain where the object is hosted
6319 mono_object_get_domain (MonoObject *obj)
6321 MONO_REQ_GC_UNSAFE_MODE;
6323 return mono_object_domain (obj);
6327 * mono_object_get_class:
6328 * @obj: object to query
6330 * Use this function to obtain the `MonoClass*` for a given `MonoObject`.
6332 * Returns: the MonoClass of the object.
6335 mono_object_get_class (MonoObject *obj)
6337 MONO_REQ_GC_UNSAFE_MODE;
6339 return mono_object_class (obj);
6342 * mono_object_get_size:
6343 * @o: object to query
6345 * Returns: the size, in bytes, of @o
6348 mono_object_get_size (MonoObject* o)
6350 MONO_REQ_GC_UNSAFE_MODE;
6352 MonoClass* klass = mono_object_class (o);
6353 if (klass == mono_defaults.string_class) {
6354 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
6355 } else if (o->vtable->rank) {
6356 MonoArray *array = (MonoArray*)o;
6357 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
6358 if (array->bounds) {
6361 size += sizeof (MonoArrayBounds) * o->vtable->rank;
6365 return mono_class_instance_size (klass);
6370 * mono_object_unbox:
6371 * @obj: object to unbox
6373 * Returns: a pointer to the start of the valuetype boxed in this
6376 * This method will assert if the object passed is not a valuetype.
6379 mono_object_unbox (MonoObject *obj)
6381 MONO_REQ_GC_UNSAFE_MODE;
6383 /* add assert for valuetypes? */
6384 g_assert (obj->vtable->klass->valuetype);
6385 return ((char*)obj) + sizeof (MonoObject);
6389 * mono_object_isinst:
6391 * @klass: a pointer to a class
6393 * Returns: @obj if @obj is derived from @klass or NULL otherwise.
6396 mono_object_isinst (MonoObject *obj, MonoClass *klass)
6398 MONO_REQ_GC_UNSAFE_MODE;
6401 MonoObject *result = mono_object_isinst_checked (obj, klass, &error);
6402 mono_error_cleanup (&error);
6408 * mono_object_isinst_checked:
6410 * @klass: a pointer to a class
6411 * @error: set on error
6413 * Returns: @obj if @obj is derived from @klass or NULL if it isn't.
6414 * On failure returns NULL and sets @error.
6417 mono_object_isinst_checked (MonoObject *obj, MonoClass *klass, MonoError *error)
6419 MONO_REQ_GC_UNSAFE_MODE;
6421 mono_error_init (error);
6423 MonoObject *result = NULL;
6426 mono_class_init (klass);
6428 if (mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
6429 result = mono_object_isinst_mbyref_checked (obj, klass, error);
6436 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
6440 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
6442 MONO_REQ_GC_UNSAFE_MODE;
6445 MonoObject *result = mono_object_isinst_mbyref_checked (obj, klass, &error);
6446 mono_error_cleanup (&error); /* FIXME better API that doesn't swallow the error */
6451 mono_object_isinst_mbyref_checked (MonoObject *obj, MonoClass *klass, MonoError *error)
6453 MONO_REQ_GC_UNSAFE_MODE;
6457 mono_error_init (error);
6464 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
6465 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
6469 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
6470 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
6473 MonoClass *oklass = vt->klass;
6474 if (mono_class_is_transparent_proxy (oklass))
6475 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
6477 mono_class_setup_supertypes (klass);
6478 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
6481 #ifndef DISABLE_REMOTING
6482 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
6484 MonoDomain *domain = mono_domain_get ();
6486 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
6487 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
6488 MonoMethod *im = NULL;
6491 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
6493 mono_error_set_not_supported (error, "Linked away.");
6496 im = mono_object_get_virtual_method (rp, im);
6499 pa [0] = mono_type_get_object_checked (domain, &klass->byval_arg, error);
6500 return_val_if_nok (error, NULL);
6503 res = mono_runtime_invoke_checked (im, rp, pa, error);
6504 return_val_if_nok (error, NULL);
6506 if (*(MonoBoolean *) mono_object_unbox(res)) {
6507 /* Update the vtable of the remote type, so it can safely cast to this new type */
6508 mono_upgrade_remote_class (domain, obj, klass);
6512 #endif /* DISABLE_REMOTING */
6517 * mono_object_castclass_mbyref:
6519 * @klass: a pointer to a class
6521 * Returns: @obj if @obj is derived from @klass, returns NULL otherwise.
6524 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
6526 MONO_REQ_GC_UNSAFE_MODE;
6529 if (!obj) return NULL;
6530 if (mono_object_isinst_mbyref_checked (obj, klass, &error)) return obj;
6531 mono_error_cleanup (&error);
6536 MonoDomain *orig_domain;
6542 str_lookup (MonoDomain *domain, gpointer user_data)
6544 MONO_REQ_GC_UNSAFE_MODE;
6546 LDStrInfo *info = (LDStrInfo *)user_data;
6547 if (info->res || domain == info->orig_domain)
6549 info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
6553 mono_string_get_pinned (MonoString *str, MonoError *error)
6555 MONO_REQ_GC_UNSAFE_MODE;
6557 mono_error_init (error);
6559 /* We only need to make a pinned version of a string if this is a moving GC */
6560 if (!mono_gc_is_moving ())
6564 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
6565 news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
6567 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
6568 news->length = mono_string_length (str);
6570 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6576 mono_string_is_interned_lookup (MonoString *str, int insert, MonoError *error)
6578 MONO_REQ_GC_UNSAFE_MODE;
6580 MonoGHashTable *ldstr_table;
6581 MonoString *s, *res;
6584 mono_error_init (error);
6586 domain = ((MonoObject *)str)->vtable->domain;
6587 ldstr_table = domain->ldstr_table;
6589 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6595 /* Allocate outside the lock */
6597 s = mono_string_get_pinned (str, error);
6598 return_val_if_nok (error, NULL);
6601 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6606 mono_g_hash_table_insert (ldstr_table, s, s);
6611 LDStrInfo ldstr_info;
6612 ldstr_info.orig_domain = domain;
6613 ldstr_info.ins = str;
6614 ldstr_info.res = NULL;
6616 mono_domain_foreach (str_lookup, &ldstr_info);
6617 if (ldstr_info.res) {
6619 * the string was already interned in some other domain:
6620 * intern it in the current one as well.
6622 mono_g_hash_table_insert (ldstr_table, str, str);
6632 * mono_string_is_interned:
6633 * @o: String to probe
6635 * Returns whether the string has been interned.
6638 mono_string_is_interned (MonoString *o)
6641 MonoString *result = mono_string_is_interned_lookup (o, FALSE, &error);
6642 /* This function does not fail. */
6643 mono_error_assert_ok (&error);
6648 * mono_string_intern:
6649 * @o: String to intern
6651 * Interns the string passed.
6652 * Returns: The interned string.
6655 mono_string_intern (MonoString *str)
6658 MonoString *result = mono_string_intern_checked (str, &error);
6659 mono_error_assert_ok (&error);
6664 * mono_string_intern_checked:
6665 * @o: String to intern
6666 * @error: set on error.
6668 * Interns the string passed.
6669 * Returns: The interned string. On failure returns NULL and sets @error
6672 mono_string_intern_checked (MonoString *str, MonoError *error)
6674 MONO_REQ_GC_UNSAFE_MODE;
6676 mono_error_init (error);
6678 return mono_string_is_interned_lookup (str, TRUE, error);
6683 * @domain: the domain where the string will be used.
6684 * @image: a metadata context
6685 * @idx: index into the user string table.
6687 * Implementation for the ldstr opcode.
6688 * Returns: a loaded string from the @image/@idx combination.
6691 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
6694 MonoString *result = mono_ldstr_checked (domain, image, idx, &error);
6695 mono_error_cleanup (&error);
6700 * mono_ldstr_checked:
6701 * @domain: the domain where the string will be used.
6702 * @image: a metadata context
6703 * @idx: index into the user string table.
6704 * @error: set on error.
6706 * Implementation for the ldstr opcode.
6707 * Returns: a loaded string from the @image/@idx combination.
6708 * On failure returns NULL and sets @error.
6711 mono_ldstr_checked (MonoDomain *domain, MonoImage *image, guint32 idx, MonoError *error)
6713 MONO_REQ_GC_UNSAFE_MODE;
6714 mono_error_init (error);
6716 if (image->dynamic) {
6717 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL, error);
6720 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6721 return NULL; /*FIXME we should probably be raising an exception here*/
6722 MonoString *str = mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx), error);
6728 * mono_ldstr_metadata_sig
6729 * @domain: the domain for the string
6730 * @sig: the signature of a metadata string
6731 * @error: set on error
6733 * Returns: a MonoString for a string stored in the metadata. On
6734 * failure returns NULL and sets @error.
6737 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error)
6739 MONO_REQ_GC_UNSAFE_MODE;
6741 mono_error_init (error);
6742 const char *str = sig;
6743 MonoString *o, *interned;
6746 len2 = mono_metadata_decode_blob_size (str, &str);
6749 o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, error);
6750 return_val_if_nok (error, NULL);
6751 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
6754 guint16 *p2 = (guint16*)mono_string_chars (o);
6755 for (i = 0; i < len2; ++i) {
6756 *p2 = GUINT16_FROM_LE (*p2);
6762 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6765 return interned; /* o will get garbage collected */
6767 o = mono_string_get_pinned (o, error);
6770 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6772 mono_g_hash_table_insert (domain->ldstr_table, o, o);
6782 * mono_string_to_utf8:
6783 * @s: a System.String
6785 * Returns the UTF8 representation for @s.
6786 * The resulting buffer needs to be freed with mono_free().
6788 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
6791 mono_string_to_utf8 (MonoString *s)
6793 MONO_REQ_GC_UNSAFE_MODE;
6796 char *result = mono_string_to_utf8_checked (s, &error);
6798 if (!mono_error_ok (&error))
6799 mono_error_raise_exception (&error);
6804 * mono_string_to_utf8_checked:
6805 * @s: a System.String
6806 * @error: a MonoError.
6808 * Converts a MonoString to its UTF8 representation. May fail; check
6809 * @error to determine whether the conversion was successful.
6810 * The resulting buffer should be freed with mono_free().
6813 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
6815 MONO_REQ_GC_UNSAFE_MODE;
6819 GError *gerror = NULL;
6821 mono_error_init (error);
6827 return g_strdup ("");
6829 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
6831 mono_error_set_argument (error, "string", "%s", gerror->message);
6832 g_error_free (gerror);
6835 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6836 if (s->length > written) {
6837 /* allocate the total length and copy the part of the string that has been converted */
6838 char *as2 = (char *)g_malloc0 (s->length);
6839 memcpy (as2, as, written);
6848 * mono_string_to_utf8_ignore:
6851 * Converts a MonoString to its UTF8 representation. Will ignore
6852 * invalid surrogate pairs.
6853 * The resulting buffer should be freed with mono_free().
6857 mono_string_to_utf8_ignore (MonoString *s)
6859 MONO_REQ_GC_UNSAFE_MODE;
6868 return g_strdup ("");
6870 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
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_image_ignore:
6886 * @s: a System.String
6888 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
6891 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
6893 MONO_REQ_GC_UNSAFE_MODE;
6895 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
6899 * mono_string_to_utf8_mp_ignore:
6900 * @s: a System.String
6902 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
6905 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
6907 MONO_REQ_GC_UNSAFE_MODE;
6909 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
6914 * mono_string_to_utf16:
6917 * Return an null-terminated array of the utf-16 chars
6918 * contained in @s. The result must be freed with g_free().
6919 * This is a temporary helper until our string implementation
6920 * is reworked to always include the null terminating char.
6923 mono_string_to_utf16 (MonoString *s)
6925 MONO_REQ_GC_UNSAFE_MODE;
6932 as = (char *)g_malloc ((s->length * 2) + 2);
6933 as [(s->length * 2)] = '\0';
6934 as [(s->length * 2) + 1] = '\0';
6937 return (gunichar2 *)(as);
6940 memcpy (as, mono_string_chars(s), s->length * 2);
6941 return (gunichar2 *)(as);
6945 * mono_string_to_utf32:
6948 * Return an null-terminated array of the UTF-32 (UCS-4) chars
6949 * contained in @s. The result must be freed with g_free().
6952 mono_string_to_utf32 (MonoString *s)
6954 MONO_REQ_GC_UNSAFE_MODE;
6956 mono_unichar4 *utf32_output = NULL;
6957 GError *error = NULL;
6958 glong items_written;
6963 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
6966 g_error_free (error);
6968 return utf32_output;
6972 * mono_string_from_utf16:
6973 * @data: the UTF16 string (LPWSTR) to convert
6975 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
6977 * Returns: a MonoString.
6980 mono_string_from_utf16 (gunichar2 *data)
6983 MonoString *result = mono_string_from_utf16_checked (data, &error);
6984 mono_error_cleanup (&error);
6989 * mono_string_from_utf16_checked:
6990 * @data: the UTF16 string (LPWSTR) to convert
6991 * @error: set on error
6993 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
6995 * Returns: a MonoString. On failure sets @error and returns NULL.
6998 mono_string_from_utf16_checked (gunichar2 *data, MonoError *error)
7001 MONO_REQ_GC_UNSAFE_MODE;
7003 mono_error_init (error);
7004 MonoDomain *domain = mono_domain_get ();
7010 while (data [len]) len++;
7012 return mono_string_new_utf16_checked (domain, data, len, error);
7016 * mono_string_from_utf32:
7017 * @data: the UTF32 string (LPWSTR) to convert
7019 * Converts a UTF32 (UCS-4)to a MonoString.
7021 * Returns: a MonoString.
7024 mono_string_from_utf32 (mono_unichar4 *data)
7027 MonoString *result = mono_string_from_utf32_checked (data, &error);
7028 mono_error_cleanup (&error);
7033 * mono_string_from_utf32_checked:
7034 * @data: the UTF32 string (LPWSTR) to convert
7035 * @error: set on error
7037 * Converts a UTF32 (UCS-4)to a MonoString.
7039 * Returns: a MonoString. On failure returns NULL and sets @error.
7042 mono_string_from_utf32_checked (mono_unichar4 *data, MonoError *error)
7044 MONO_REQ_GC_UNSAFE_MODE;
7046 mono_error_init (error);
7047 MonoString* result = NULL;
7048 mono_unichar2 *utf16_output = NULL;
7049 GError *gerror = NULL;
7050 glong items_written;
7056 while (data [len]) len++;
7058 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &gerror);
7061 g_error_free (gerror);
7063 result = mono_string_from_utf16_checked (utf16_output, error);
7064 g_free (utf16_output);
7069 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
7071 MONO_REQ_GC_UNSAFE_MODE;
7078 r = mono_string_to_utf8_ignore (s);
7080 r = mono_string_to_utf8_checked (s, error);
7081 if (!mono_error_ok (error))
7088 len = strlen (r) + 1;
7090 mp_s = (char *)mono_mempool_alloc (mp, len);
7092 mp_s = (char *)mono_image_alloc (image, len);
7094 memcpy (mp_s, r, len);
7102 * mono_string_to_utf8_image:
7103 * @s: a System.String
7105 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
7108 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
7110 MONO_REQ_GC_UNSAFE_MODE;
7112 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
7116 * mono_string_to_utf8_mp:
7117 * @s: a System.String
7119 * Same as mono_string_to_utf8, but allocate the string from a mempool.
7122 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
7124 MONO_REQ_GC_UNSAFE_MODE;
7126 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
7130 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
7133 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
7135 eh_callbacks = *cbs;
7138 MonoRuntimeExceptionHandlingCallbacks *
7139 mono_get_eh_callbacks (void)
7141 return &eh_callbacks;
7145 * mono_raise_exception:
7146 * @ex: exception object
7148 * Signal the runtime that the exception @ex has been raised in unmanaged code.
7151 mono_raise_exception (MonoException *ex)
7153 MONO_REQ_GC_UNSAFE_MODE;
7156 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
7157 * that will cause gcc to omit the function epilog, causing problems when
7158 * the JIT tries to walk the stack, since the return address on the stack
7159 * will point into the next function in the executable, not this one.
7161 eh_callbacks.mono_raise_exception (ex);
7165 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
7167 MONO_REQ_GC_UNSAFE_MODE;
7169 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
7173 * mono_wait_handle_new:
7174 * @domain: Domain where the object will be created
7175 * @handle: Handle for the wait handle
7176 * @error: set on error.
7178 * Returns: A new MonoWaitHandle created in the given domain for the
7179 * given handle. On failure returns NULL and sets @rror.
7182 mono_wait_handle_new (MonoDomain *domain, HANDLE handle, MonoError *error)
7184 MONO_REQ_GC_UNSAFE_MODE;
7186 MonoWaitHandle *res;
7187 gpointer params [1];
7188 static MonoMethod *handle_set;
7190 mono_error_init (error);
7191 res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, error);
7192 return_val_if_nok (error, NULL);
7194 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
7196 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
7198 params [0] = &handle;
7200 mono_runtime_invoke_checked (handle_set, res, params, error);
7205 mono_wait_handle_get_handle (MonoWaitHandle *handle)
7207 MONO_REQ_GC_UNSAFE_MODE;
7209 static MonoClassField *f_safe_handle = NULL;
7212 if (!f_safe_handle) {
7213 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safeWaitHandle");
7214 g_assert (f_safe_handle);
7217 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
7223 mono_runtime_capture_context (MonoDomain *domain, MonoError *error)
7225 MONO_REQ_GC_UNSAFE_MODE;
7227 RuntimeInvokeFunction runtime_invoke;
7229 mono_error_init (error);
7231 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
7232 MonoMethod *method = mono_get_context_capture_method ();
7233 MonoMethod *wrapper;
7236 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
7237 domain->capture_context_runtime_invoke = mono_compile_method_checked (wrapper, error);
7238 return_val_if_nok (error, NULL);
7239 domain->capture_context_method = mono_compile_method_checked (method, error);
7240 return_val_if_nok (error, NULL);
7243 runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
7245 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
7248 * mono_async_result_new:
7249 * @domain:domain where the object will be created.
7250 * @handle: wait handle.
7251 * @state: state to pass to AsyncResult
7252 * @data: C closure data.
7253 * @error: set on error.
7255 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
7256 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
7257 * On failure returns NULL and sets @error.
7261 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data, MonoError *error)
7263 MONO_REQ_GC_UNSAFE_MODE;
7265 mono_error_init (error);
7266 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, error);
7267 return_val_if_nok (error, NULL);
7268 MonoObject *context = mono_runtime_capture_context (domain, error);
7269 return_val_if_nok (error, NULL);
7270 /* we must capture the execution context from the original thread */
7272 MONO_OBJECT_SETREF (res, execution_context, context);
7273 /* note: result may be null if the flow is suppressed */
7276 res->data = (void **)data;
7277 MONO_OBJECT_SETREF (res, object_data, object_data);
7278 MONO_OBJECT_SETREF (res, async_state, state);
7279 MonoWaitHandle *wait_handle = mono_wait_handle_new (domain, handle, error);
7280 return_val_if_nok (error, NULL);
7282 MONO_OBJECT_SETREF (res, handle, (MonoObject *) wait_handle);
7284 res->sync_completed = FALSE;
7285 res->completed = FALSE;
7291 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
7293 MONO_REQ_GC_UNSAFE_MODE;
7300 g_assert (ares->async_delegate);
7302 ac = (MonoAsyncCall*) ares->object_data;
7304 res = mono_runtime_delegate_invoke_checked (ares->async_delegate, (void**) &ares->async_state, &error);
7305 if (mono_error_set_pending_exception (&error))
7308 gpointer wait_event = NULL;
7310 ac->msg->exc = NULL;
7311 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args, &error);
7312 if (mono_error_set_pending_exception (&error))
7314 MONO_OBJECT_SETREF (ac, res, res);
7316 mono_monitor_enter ((MonoObject*) ares);
7317 ares->completed = 1;
7319 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
7320 mono_monitor_exit ((MonoObject*) ares);
7322 if (wait_event != NULL)
7323 SetEvent (wait_event);
7325 if (ac->cb_method) {
7326 mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
7327 if (mono_error_set_pending_exception (&error))
7336 mono_message_init (MonoDomain *domain,
7337 MonoMethodMessage *this_obj,
7338 MonoReflectionMethod *method,
7339 MonoArray *out_args,
7342 MONO_REQ_GC_UNSAFE_MODE;
7344 static MonoClass *object_array_klass;
7345 static MonoClass *byte_array_klass;
7346 static MonoClass *string_array_klass;
7347 mono_error_init (error);
7348 MonoMethodSignature *sig = mono_method_signature (method->method);
7355 if (!object_array_klass) {
7358 klass = mono_array_class_get (mono_defaults.byte_class, 1);
7360 byte_array_klass = klass;
7362 klass = mono_array_class_get (mono_defaults.string_class, 1);
7364 string_array_klass = klass;
7366 klass = mono_array_class_get (mono_defaults.object_class, 1);
7369 mono_atomic_store_release (&object_array_klass, klass);
7372 MONO_OBJECT_SETREF (this_obj, method, method);
7374 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), sig->param_count, error);
7375 return_val_if_nok (error, FALSE);
7377 MONO_OBJECT_SETREF (this_obj, args, arr);
7379 arr = mono_array_new_specific_checked (mono_class_vtable (domain, byte_array_klass), sig->param_count, error);
7380 return_val_if_nok (error, FALSE);
7382 MONO_OBJECT_SETREF (this_obj, arg_types, arr);
7384 this_obj->async_result = NULL;
7385 this_obj->call_type = CallType_Sync;
7387 names = g_new (char *, sig->param_count);
7388 mono_method_get_param_names (method->method, (const char **) names);
7390 arr = mono_array_new_specific_checked (mono_class_vtable (domain, string_array_klass), sig->param_count, error);
7394 MONO_OBJECT_SETREF (this_obj, names, arr);
7396 for (i = 0; i < sig->param_count; i++) {
7397 name = mono_string_new_checked (domain, names [i], error);
7400 mono_array_setref (this_obj->names, i, name);
7404 for (i = 0, j = 0; i < sig->param_count; i++) {
7405 if (sig->params [i]->byref) {
7407 MonoObject* arg = (MonoObject *)mono_array_get (out_args, gpointer, j);
7408 mono_array_setref (this_obj->args, i, arg);
7412 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
7416 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
7419 mono_array_set (this_obj->arg_types, guint8, i, arg_type);
7428 #ifndef DISABLE_REMOTING
7430 * mono_remoting_invoke:
7431 * @real_proxy: pointer to a RealProxy object
7432 * @msg: The MonoMethodMessage to execute
7433 * @exc: used to store exceptions
7434 * @out_args: used to store output arguments
7436 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
7437 * IMessage interface and it is not trivial to extract results from there. So
7438 * we call an helper method PrivateInvoke instead of calling
7439 * RealProxy::Invoke() directly.
7441 * Returns: the result object.
7444 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, MonoObject **exc, MonoArray **out_args, MonoError *error)
7446 MONO_REQ_GC_UNSAFE_MODE;
7449 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
7454 mono_error_init (error);
7456 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
7459 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
7461 mono_error_set_not_supported (error, "Linked away.");
7464 real_proxy->vtable->domain->private_invoke_method = im;
7467 pa [0] = real_proxy;
7472 o = mono_runtime_try_invoke (im, NULL, pa, exc, error);
7473 return_val_if_nok (error, NULL);
7480 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
7481 MonoObject **exc, MonoArray **out_args, MonoError *error)
7483 MONO_REQ_GC_UNSAFE_MODE;
7485 static MonoClass *object_array_klass;
7486 mono_error_init (error);
7490 MonoMethodSignature *sig;
7492 int i, j, outarg_count = 0;
7494 #ifndef DISABLE_REMOTING
7495 if (target && mono_object_is_transparent_proxy (target)) {
7496 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
7497 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7498 target = tp->rp->unwrapped_server;
7500 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args, error);
7505 domain = mono_domain_get ();
7506 method = msg->method->method;
7507 sig = mono_method_signature (method);
7509 for (i = 0; i < sig->param_count; i++) {
7510 if (sig->params [i]->byref)
7514 if (!object_array_klass) {
7517 klass = mono_array_class_get (mono_defaults.object_class, 1);
7520 mono_memory_barrier ();
7521 object_array_klass = klass;
7524 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, error);
7525 return_val_if_nok (error, NULL);
7527 mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
7530 MonoObject *ret = mono_runtime_try_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc, error);
7531 return_val_if_nok (error, NULL);
7533 for (i = 0, j = 0; i < sig->param_count; i++) {
7534 if (sig->params [i]->byref) {
7536 arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
7537 mono_array_setref (*out_args, j, arg);
7546 * mono_object_to_string:
7548 * @exc: Any exception thrown by ToString (). May be NULL.
7550 * Returns: the result of calling ToString () on an object.
7553 mono_object_to_string (MonoObject *obj, MonoObject **exc)
7555 MONO_REQ_GC_UNSAFE_MODE;
7557 static MonoMethod *to_string = NULL;
7566 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
7568 method = mono_object_get_virtual_method (obj, to_string);
7570 // Unbox value type if needed
7571 if (mono_class_is_valuetype (mono_method_get_class (method))) {
7572 target = mono_object_unbox (obj);
7576 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
7577 if (*exc == NULL && !mono_error_ok (&error))
7578 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
7580 mono_error_cleanup (&error);
7582 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
7583 mono_error_raise_exception (&error); /* FIXME don't raise here */
7590 * mono_print_unhandled_exception:
7591 * @exc: The exception
7593 * Prints the unhandled exception.
7596 mono_print_unhandled_exception (MonoObject *exc)
7598 MONO_REQ_GC_UNSAFE_MODE;
7601 char *message = (char*)"";
7602 gboolean free_message = FALSE;
7605 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
7606 message = g_strdup ("OutOfMemoryException");
7607 free_message = TRUE;
7608 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
7609 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
7610 free_message = TRUE;
7613 if (((MonoException*)exc)->native_trace_ips) {
7614 message = mono_exception_get_native_backtrace ((MonoException*)exc);
7615 free_message = TRUE;
7617 MonoObject *other_exc = NULL;
7618 str = mono_object_to_string (exc, &other_exc);
7620 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
7621 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
7623 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
7624 original_backtrace, nested_backtrace);
7626 g_free (original_backtrace);
7627 g_free (nested_backtrace);
7628 free_message = TRUE;
7630 message = mono_string_to_utf8_checked (str, &error);
7631 if (!mono_error_ok (&error)) {
7632 mono_error_cleanup (&error);
7633 message = (char *) "";
7635 free_message = TRUE;
7642 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
7643 * exc->vtable->klass->name, message);
7645 g_printerr ("\nUnhandled Exception:\n%s\n", message);
7652 * mono_delegate_ctor_with_method:
7653 * @this: pointer to an uninitialized delegate object
7654 * @target: target object
7655 * @addr: pointer to native code
7657 * @error: set on error.
7659 * Initialize a delegate and sets a specific method, not the one
7660 * associated with addr. This is useful when sharing generic code.
7661 * In that case addr will most probably not be associated with the
7662 * correct instantiation of the method.
7663 * On failure returns FALSE and sets @error.
7666 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method, MonoError *error)
7668 MONO_REQ_GC_UNSAFE_MODE;
7670 mono_error_init (error);
7671 MonoDelegate *delegate = (MonoDelegate *)this_obj;
7673 g_assert (this_obj);
7676 g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
7679 delegate->method = method;
7681 mono_stats.delegate_creations++;
7683 #ifndef DISABLE_REMOTING
7684 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
7686 method = mono_marshal_get_remoting_invoke (method);
7687 delegate->method_ptr = mono_compile_method_checked (method, error);
7688 return_val_if_nok (error, FALSE);
7689 MONO_OBJECT_SETREF (delegate, target, target);
7693 delegate->method_ptr = addr;
7694 MONO_OBJECT_SETREF (delegate, target, target);
7697 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
7698 if (callbacks.init_delegate)
7699 callbacks.init_delegate (delegate);
7704 * mono_delegate_ctor:
7705 * @this: pointer to an uninitialized delegate object
7706 * @target: target object
7707 * @addr: pointer to native code
7708 * @error: set on error.
7710 * This is used to initialize a delegate.
7711 * On failure returns FALSE and sets @error.
7714 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoError *error)
7716 MONO_REQ_GC_UNSAFE_MODE;
7718 mono_error_init (error);
7719 MonoDomain *domain = mono_domain_get ();
7721 MonoMethod *method = NULL;
7725 ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
7727 if (!ji && domain != mono_get_root_domain ())
7728 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
7730 method = mono_jit_info_get_method (ji);
7731 g_assert (!method->klass->generic_container);
7734 return mono_delegate_ctor_with_method (this_obj, target, addr, method, error);
7738 * mono_method_call_message_new:
7739 * @method: method to encapsulate
7740 * @params: parameters to the method
7741 * @invoke: optional, delegate invoke.
7742 * @cb: async callback delegate.
7743 * @state: state passed to the async callback.
7744 * @error: set on error.
7746 * Translates arguments pointers into a MonoMethodMessage.
7747 * On failure returns NULL and sets @error.
7750 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
7751 MonoDelegate **cb, MonoObject **state, MonoError *error)
7753 MONO_REQ_GC_UNSAFE_MODE;
7755 mono_error_init (error);
7757 MonoDomain *domain = mono_domain_get ();
7758 MonoMethodSignature *sig = mono_method_signature (method);
7759 MonoMethodMessage *msg;
7762 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
7763 return_val_if_nok (error, NULL);
7766 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, error);
7767 return_val_if_nok (error, NULL);
7768 mono_message_init (domain, msg, rm, NULL, error);
7769 return_val_if_nok (error, NULL);
7770 count = sig->param_count - 2;
7772 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
7773 return_val_if_nok (error, NULL);
7774 mono_message_init (domain, msg, rm, NULL, error);
7775 return_val_if_nok (error, NULL);
7776 count = sig->param_count;
7779 for (i = 0; i < count; i++) {
7784 if (sig->params [i]->byref)
7785 vpos = *((gpointer *)params [i]);
7789 klass = mono_class_from_mono_type (sig->params [i]);
7791 if (klass->valuetype) {
7792 arg = mono_value_box_checked (domain, klass, vpos, error);
7793 return_val_if_nok (error, NULL);
7795 arg = *((MonoObject **)vpos);
7797 mono_array_setref (msg->args, i, arg);
7800 if (cb != NULL && state != NULL) {
7801 *cb = *((MonoDelegate **)params [i]);
7803 *state = *((MonoObject **)params [i]);
7810 * mono_method_return_message_restore:
7812 * Restore results from message based processing back to arguments pointers
7815 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args, MonoError *error)
7817 MONO_REQ_GC_UNSAFE_MODE;
7819 mono_error_init (error);
7821 MonoMethodSignature *sig = mono_method_signature (method);
7822 int i, j, type, size, out_len;
7824 if (out_args == NULL)
7826 out_len = mono_array_length (out_args);
7830 for (i = 0, j = 0; i < sig->param_count; i++) {
7831 MonoType *pt = sig->params [i];
7836 mono_error_set_execution_engine (error, "The proxy call returned an incorrect number of output arguments");
7840 arg = (char *)mono_array_get (out_args, gpointer, j);
7843 g_assert (type != MONO_TYPE_VOID);
7845 if (MONO_TYPE_IS_REFERENCE (pt)) {
7846 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
7849 MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
7850 size = mono_class_value_size (klass, NULL);
7851 if (klass->has_references)
7852 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
7854 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
7856 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
7857 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
7866 #ifndef DISABLE_REMOTING
7869 * mono_load_remote_field:
7870 * @this: pointer to an object
7871 * @klass: klass of the object containing @field
7872 * @field: the field to load
7873 * @res: a storage to store the result
7875 * This method is called by the runtime on attempts to load fields of
7876 * transparent proxy objects. @this points to such TP, @klass is the class of
7877 * the object containing @field. @res is a storage location which can be
7878 * used to store the result.
7880 * Returns: an address pointing to the value of field.
7883 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
7886 gpointer result = mono_load_remote_field_checked (this_obj, klass, field, res, &error);
7887 mono_error_cleanup (&error);
7892 * mono_load_remote_field_checked:
7893 * @this: pointer to an object
7894 * @klass: klass of the object containing @field
7895 * @field: the field to load
7896 * @res: a storage to store the result
7897 * @error: set on error
7899 * This method is called by the runtime on attempts to load fields of
7900 * transparent proxy objects. @this points to such TP, @klass is the class of
7901 * the object containing @field. @res is a storage location which can be
7902 * used to store the result.
7904 * Returns: an address pointing to the value of field. On failure returns NULL and sets @error.
7907 mono_load_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res, MonoError *error)
7909 MONO_REQ_GC_UNSAFE_MODE;
7911 static MonoMethod *getter = NULL;
7913 mono_error_init (error);
7915 MonoDomain *domain = mono_domain_get ();
7916 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7917 MonoClass *field_class;
7918 MonoMethodMessage *msg;
7919 MonoArray *out_args;
7923 g_assert (mono_object_is_transparent_proxy (this_obj));
7924 g_assert (res != NULL);
7926 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7927 mono_field_get_value (tp->rp->unwrapped_server, field, res);
7932 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
7934 mono_error_set_not_supported (error, "Linked away.");
7939 field_class = mono_class_from_mono_type (field->type);
7941 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
7942 return_val_if_nok (error, NULL);
7943 out_args = mono_array_new_checked (domain, mono_defaults.object_class, 1, error);
7944 return_val_if_nok (error, NULL);
7945 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, error);
7946 return_val_if_nok (error, NULL);
7947 mono_message_init (domain, msg, rm, out_args, error);
7948 return_val_if_nok (error, NULL);
7950 full_name = mono_type_get_full_name (klass);
7951 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7952 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7955 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
7956 return_val_if_nok (error, NULL);
7959 mono_error_set_exception_instance (error, (MonoException *)exc);
7963 if (mono_array_length (out_args) == 0)
7966 mono_gc_wbarrier_generic_store (res, mono_array_get (out_args, MonoObject *, 0));
7968 if (field_class->valuetype) {
7969 return ((char *)*res) + sizeof (MonoObject);
7975 * mono_load_remote_field_new:
7980 * Missing documentation.
7983 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
7987 MonoObject *result = mono_load_remote_field_new_checked (this_obj, klass, field, &error);
7988 mono_error_cleanup (&error);
7993 * mono_load_remote_field_new_icall:
7994 * @this: pointer to an object
7995 * @klass: klass of the object containing @field
7996 * @field: the field to load
7998 * This method is called by the runtime on attempts to load fields of
7999 * transparent proxy objects. @this points to such TP, @klass is the class of
8000 * the object containing @field.
8002 * Returns: a freshly allocated object containing the value of the
8003 * field. On failure returns NULL and throws an exception.
8006 mono_load_remote_field_new_icall (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
8009 MonoObject *result = mono_load_remote_field_new_checked (this_obj, klass, field, &error);
8010 mono_error_set_pending_exception (&error);
8015 * mono_load_remote_field_new_checked:
8016 * @this: pointer to an object
8017 * @klass: klass of the object containing @field
8018 * @field: the field to load
8019 * @error: set on error.
8021 * This method is called by the runtime on attempts to load fields of
8022 * transparent proxy objects. @this points to such TP, @klass is the class of
8023 * the object containing @field.
8025 * Returns: a freshly allocated object containing the value of the field. On failure returns NULL and sets @error.
8028 mono_load_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoError *error)
8030 MONO_REQ_GC_UNSAFE_MODE;
8032 mono_error_init (error);
8034 static MonoMethod *getter = NULL;
8035 MonoDomain *domain = mono_domain_get ();
8036 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8037 MonoClass *field_class;
8038 MonoMethodMessage *msg;
8039 MonoArray *out_args;
8040 MonoObject *exc, *res;
8043 g_assert (mono_object_is_transparent_proxy (this_obj));
8045 field_class = mono_class_from_mono_type (field->type);
8047 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8049 if (field_class->valuetype) {
8050 res = mono_object_new_checked (domain, field_class, error);
8051 return_val_if_nok (error, NULL);
8052 val = ((gchar *) res) + sizeof (MonoObject);
8056 mono_field_get_value (tp->rp->unwrapped_server, field, val);
8061 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
8063 mono_error_set_not_supported (error, "Linked away.");
8068 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8069 return_val_if_nok (error, NULL);
8070 out_args = mono_array_new_checked (domain, mono_defaults.object_class, 1, error);
8071 return_val_if_nok (error, NULL);
8073 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, error);
8074 return_val_if_nok (error, NULL);
8075 mono_message_init (domain, msg, rm, out_args, error);
8076 return_val_if_nok (error, NULL);
8078 full_name = mono_type_get_full_name (klass);
8079 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
8080 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
8083 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8084 return_val_if_nok (error, NULL);
8087 mono_error_set_exception_instance (error, (MonoException *)exc);
8091 if (mono_array_length (out_args) == 0)
8094 res = mono_array_get (out_args, MonoObject *, 0);
8100 * mono_store_remote_field:
8101 * @this_obj: pointer to an object
8102 * @klass: klass of the object containing @field
8103 * @field: the field to load
8104 * @val: the value/object to store
8106 * This method is called by the runtime on attempts to store fields of
8107 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
8108 * the object containing @field. @val is the new value to store in @field.
8111 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
8114 (void) mono_store_remote_field_checked (this_obj, klass, field, val, &error);
8115 mono_error_cleanup (&error);
8119 * mono_store_remote_field_checked:
8120 * @this_obj: pointer to an object
8121 * @klass: klass of the object containing @field
8122 * @field: the field to load
8123 * @val: the value/object to store
8124 * @error: set on error
8126 * This method is called by the runtime on attempts to store fields of
8127 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
8128 * the object containing @field. @val is the new value to store in @field.
8130 * Returns: on success returns TRUE, on failure returns FALSE and sets @error.
8133 mono_store_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val, MonoError *error)
8136 MONO_REQ_GC_UNSAFE_MODE;
8138 static MonoMethod *setter = NULL;
8140 MonoDomain *domain = mono_domain_get ();
8141 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8142 MonoClass *field_class;
8143 MonoMethodMessage *msg;
8144 MonoArray *out_args;
8149 mono_error_init (error);
8151 g_assert (mono_object_is_transparent_proxy (this_obj));
8153 field_class = mono_class_from_mono_type (field->type);
8155 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8156 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
8157 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
8162 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
8164 mono_error_set_not_supported (error, "Linked away.");
8169 if (field_class->valuetype) {
8170 arg = mono_value_box_checked (domain, field_class, val, error);
8171 return_val_if_nok (error, FALSE);
8173 arg = *((MonoObject **)val);
8176 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8177 return_val_if_nok (error, FALSE);
8178 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, setter, NULL, error);
8179 return_val_if_nok (error, FALSE);
8180 mono_message_init (domain, msg, rm, NULL, error);
8181 return_val_if_nok (error, FALSE);
8183 full_name = mono_type_get_full_name (klass);
8184 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
8185 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
8186 mono_array_setref (msg->args, 2, arg);
8189 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8190 return_val_if_nok (error, FALSE);
8193 mono_error_set_exception_instance (error, (MonoException *)exc);
8200 * mono_store_remote_field_new:
8206 * Missing documentation
8209 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
8212 (void) mono_store_remote_field_new_checked (this_obj, klass, field, arg, &error);
8213 mono_error_cleanup (&error);
8217 * mono_store_remote_field_new_icall:
8223 * Missing documentation
8226 mono_store_remote_field_new_icall (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
8229 (void) mono_store_remote_field_new_checked (this_obj, klass, field, arg, &error);
8230 mono_error_set_pending_exception (&error);
8234 * mono_store_remote_field_new_checked:
8241 * Missing documentation
8244 mono_store_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg, MonoError *error)
8246 MONO_REQ_GC_UNSAFE_MODE;
8248 static MonoMethod *setter = NULL;
8249 MonoDomain *domain = mono_domain_get ();
8250 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8251 MonoClass *field_class;
8252 MonoMethodMessage *msg;
8253 MonoArray *out_args;
8257 mono_error_init (error);
8259 g_assert (mono_object_is_transparent_proxy (this_obj));
8261 field_class = mono_class_from_mono_type (field->type);
8263 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8264 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
8265 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
8270 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
8272 mono_error_set_not_supported (error, "Linked away.");
8277 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8278 return_val_if_nok (error, FALSE);
8279 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, setter, NULL, error);
8280 return_val_if_nok (error, FALSE);
8281 mono_message_init (domain, msg, rm, NULL, error);
8282 return_val_if_nok (error, FALSE);
8284 full_name = mono_type_get_full_name (klass);
8285 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
8286 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
8287 mono_array_setref (msg->args, 2, arg);
8290 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8291 return_val_if_nok (error, FALSE);
8294 mono_error_set_exception_instance (error, (MonoException *)exc);
8302 * mono_create_ftnptr:
8304 * Given a function address, create a function descriptor for it.
8305 * This is only needed on some platforms.
8308 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
8310 return callbacks.create_ftnptr (domain, addr);
8314 * mono_get_addr_from_ftnptr:
8316 * Given a pointer to a function descriptor, return the function address.
8317 * This is only needed on some platforms.
8320 mono_get_addr_from_ftnptr (gpointer descr)
8322 return callbacks.get_addr_from_ftnptr (descr);
8326 * mono_string_chars:
8329 * Returns a pointer to the UCS16 characters stored in the MonoString
8332 mono_string_chars (MonoString *s)
8334 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
8340 * mono_string_length:
8343 * Returns the lenght in characters of the string
8346 mono_string_length (MonoString *s)
8348 MONO_REQ_GC_UNSAFE_MODE;
8354 * mono_array_length:
8355 * @array: a MonoArray*
8357 * Returns the total number of elements in the array. This works for
8358 * both vectors and multidimensional arrays.
8361 mono_array_length (MonoArray *array)
8363 MONO_REQ_GC_UNSAFE_MODE;
8365 return array->max_length;
8369 * mono_array_addr_with_size:
8370 * @array: a MonoArray*
8371 * @size: size of the array elements
8372 * @idx: index into the array
8374 * Use this function to obtain the address for the @idx item on the
8375 * @array containing elements of size @size.
8377 * This method performs no bounds checking or type checking.
8379 * Returns the address of the @idx element in the array.
8382 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
8384 MONO_REQ_GC_UNSAFE_MODE;
8386 return ((char*)(array)->vector) + size * idx;
8391 mono_glist_to_array (GList *list, MonoClass *eclass, MonoError *error)
8393 MonoDomain *domain = mono_domain_get ();
8397 mono_error_init (error);
8401 len = g_list_length (list);
8402 res = mono_array_new_checked (domain, eclass, len, error);
8403 return_val_if_nok (error, NULL);
8405 for (i = 0; list; list = list->next, i++)
8406 mono_array_set (res, gpointer, i, list->data);
8413 * The following section is purely to declare prototypes and
8414 * document the API, as these C files are processed by our
8420 * @array: array to alter
8421 * @element_type: A C type name, this macro will use the sizeof(type) to determine the element size
8422 * @index: index into the array
8423 * @value: value to set
8425 * Value Type version: This sets the @index's element of the @array
8426 * with elements of size sizeof(type) to the provided @value.
8428 * This macro does not attempt to perform type checking or bounds checking.
8430 * Use this to set value types in a `MonoArray`.
8432 void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
8437 * mono_array_setref:
8438 * @array: array to alter
8439 * @index: index into the array
8440 * @value: value to set
8442 * Reference Type version: This sets the @index's element of the
8443 * @array with elements of size sizeof(type) to the provided @value.
8445 * This macro does not attempt to perform type checking or bounds checking.
8447 * Use this to reference types in a `MonoArray`.
8449 void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
8455 * @array: array on which to operate on
8456 * @element_type: C element type (example: MonoString *, int, MonoObject *)
8457 * @index: index into the array
8459 * Use this macro to retrieve the @index element of an @array and
8460 * extract the value assuming that the elements of the array match
8461 * the provided type value.
8463 * This method can be used with both arrays holding value types and
8464 * reference types. For reference types, the @type parameter should
8465 * be a `MonoObject*` or any subclass of it, like `MonoString*`.
8467 * This macro does not attempt to perform type checking or bounds checking.
8469 * Returns: The element at the @index position in the @array.
8471 Type mono_array_get (MonoArray *array, Type element_type, uintptr_t index)