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)
19 #include <mono/metadata/mono-endian.h>
20 #include <mono/metadata/tabledefs.h>
21 #include <mono/metadata/tokentype.h>
22 #include <mono/metadata/loader.h>
23 #include <mono/metadata/object.h>
24 #include <mono/metadata/gc-internals.h>
25 #include <mono/metadata/exception.h>
26 #include <mono/metadata/exception-internals.h>
27 #include <mono/metadata/domain-internals.h>
28 #include "mono/metadata/metadata-internals.h"
29 #include "mono/metadata/class-internals.h"
30 #include <mono/metadata/assembly.h>
31 #include <mono/metadata/marshal.h>
32 #include "mono/metadata/debug-helpers.h"
33 #include "mono/metadata/marshal.h"
34 #include <mono/metadata/threads.h>
35 #include <mono/metadata/threads-types.h>
36 #include <mono/metadata/environment.h>
37 #include "mono/metadata/profiler-private.h"
38 #include "mono/metadata/security-manager.h"
39 #include "mono/metadata/mono-debug-debugger.h"
40 #include <mono/metadata/gc-internals.h>
41 #include <mono/metadata/verify-internals.h>
42 #include <mono/metadata/reflection-internals.h>
43 #include <mono/utils/strenc.h>
44 #include <mono/utils/mono-counters.h>
45 #include <mono/utils/mono-error-internals.h>
46 #include <mono/utils/mono-memory-model.h>
47 #include <mono/utils/checked-build.h>
48 #include <mono/utils/mono-threads.h>
49 #include "cominterop.h"
52 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value);
55 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig);
58 free_main_args (void);
61 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error);
63 /* Class lazy loading functions */
64 static GENERATE_GET_CLASS_WITH_CACHE (pointer, System.Reflection, Pointer)
65 static GENERATE_GET_CLASS_WITH_CACHE (remoting_services, System.Runtime.Remoting, RemotingServices)
66 static GENERATE_GET_CLASS_WITH_CACHE (unhandled_exception_event_args, System, UnhandledExceptionEventArgs)
67 static GENERATE_GET_CLASS_WITH_CACHE (sta_thread_attribute, System, STAThreadAttribute)
68 static GENERATE_GET_CLASS_WITH_CACHE (activation_services, System.Runtime.Remoting.Activation, ActivationServices)
71 #define ldstr_lock() mono_os_mutex_lock (&ldstr_section)
72 #define ldstr_unlock() mono_os_mutex_unlock (&ldstr_section)
73 static mono_mutex_t ldstr_section;
76 * mono_runtime_object_init:
77 * @this_obj: the object to initialize
79 * This function calls the zero-argument constructor (which must
80 * exist) for the given object.
83 mono_runtime_object_init (MonoObject *this_obj)
86 mono_runtime_object_init_checked (this_obj, &error);
87 mono_error_assert_ok (&error);
91 * mono_runtime_object_init_checked:
92 * @this_obj: the object to initialize
93 * @error: set on error.
95 * This function calls the zero-argument constructor (which must
96 * exist) for the given object and returns TRUE on success, or FALSE
97 * on error and sets @error.
100 mono_runtime_object_init_checked (MonoObject *this_obj, MonoError *error)
102 MONO_REQ_GC_UNSAFE_MODE;
104 MonoMethod *method = NULL;
105 MonoClass *klass = this_obj->vtable->klass;
107 mono_error_init (error);
108 method = mono_class_get_method_from_name (klass, ".ctor", 0);
110 g_error ("Could not lookup zero argument constructor for class %s", mono_type_get_full_name (klass));
112 if (method->klass->valuetype)
113 this_obj = (MonoObject *)mono_object_unbox (this_obj);
115 mono_runtime_invoke_checked (method, this_obj, NULL, error);
116 return is_ok (error);
119 /* The pseudo algorithm for type initialization from the spec
120 Note it doesn't say anything about domains - only threads.
122 2. If the type is initialized you are done.
123 2.1. If the type is not yet initialized, try to take an
125 2.2. If successful, record this thread as responsible for
126 initializing the type and proceed to step 2.3.
127 2.2.1. If not, see whether this thread or any thread
128 waiting for this thread to complete already holds the lock.
129 2.2.2. If so, return since blocking would create a deadlock. This thread
130 will now see an incompletely initialized state for the type,
131 but no deadlock will arise.
132 2.2.3 If not, block until the type is initialized then return.
133 2.3 Initialize the parent type and then all interfaces implemented
135 2.4 Execute the type initialization code for this type.
136 2.5 Mark the type as initialized, release the initialization lock,
137 awaken any threads waiting for this type to be initialized,
144 MonoNativeThreadId initializing_tid;
145 guint32 waiting_count;
147 MonoCoopMutex initialization_section;
148 } TypeInitializationLock;
150 /* for locking access to type_initialization_hash and blocked_thread_hash */
151 static MonoCoopMutex type_initialization_section;
154 mono_type_initialization_lock (void)
156 /* The critical sections protected by this lock in mono_runtime_class_init_full () can block */
157 mono_coop_mutex_lock (&type_initialization_section);
161 mono_type_initialization_unlock (void)
163 mono_coop_mutex_unlock (&type_initialization_section);
167 mono_type_init_lock (TypeInitializationLock *lock)
169 MONO_REQ_GC_NEUTRAL_MODE;
171 mono_coop_mutex_lock (&lock->initialization_section);
175 mono_type_init_unlock (TypeInitializationLock *lock)
177 mono_coop_mutex_unlock (&lock->initialization_section);
180 /* from vtable to lock */
181 static GHashTable *type_initialization_hash;
183 /* from thread id to thread id being waited on */
184 static GHashTable *blocked_thread_hash;
187 static MonoThread *main_thread;
189 /* Functions supplied by the runtime */
190 static MonoRuntimeCallbacks callbacks;
193 * mono_thread_set_main:
194 * @thread: thread to set as the main thread
196 * This function can be used to instruct the runtime to treat @thread
197 * as the main thread, ie, the thread that would normally execute the Main()
198 * method. This basically means that at the end of @thread, the runtime will
199 * wait for the existing foreground threads to quit and other such details.
202 mono_thread_set_main (MonoThread *thread)
204 MONO_REQ_GC_UNSAFE_MODE;
206 static gboolean registered = FALSE;
209 MONO_GC_REGISTER_ROOT_SINGLE (main_thread, MONO_ROOT_SOURCE_THREADING, "main thread object");
213 main_thread = thread;
217 mono_thread_get_main (void)
219 MONO_REQ_GC_UNSAFE_MODE;
225 mono_type_initialization_init (void)
227 mono_coop_mutex_init_recursive (&type_initialization_section);
228 type_initialization_hash = g_hash_table_new (NULL, NULL);
229 blocked_thread_hash = g_hash_table_new (NULL, NULL);
230 mono_os_mutex_init_recursive (&ldstr_section);
234 mono_type_initialization_cleanup (void)
237 /* This is causing race conditions with
238 * mono_release_type_locks
240 mono_coop_mutex_destroy (&type_initialization_section);
241 g_hash_table_destroy (type_initialization_hash);
242 type_initialization_hash = NULL;
244 mono_os_mutex_destroy (&ldstr_section);
245 g_hash_table_destroy (blocked_thread_hash);
246 blocked_thread_hash = NULL;
252 * get_type_init_exception_for_vtable:
254 * Return the stored type initialization exception for VTABLE.
256 static MonoException*
257 get_type_init_exception_for_vtable (MonoVTable *vtable)
259 MONO_REQ_GC_UNSAFE_MODE;
262 MonoDomain *domain = vtable->domain;
263 MonoClass *klass = vtable->klass;
267 if (!vtable->init_failed)
268 g_error ("Trying to get the init exception for a non-failed vtable of class %s", mono_type_get_full_name (klass));
271 * If the initializing thread was rudely aborted, the exception is not stored
275 mono_domain_lock (domain);
276 if (domain->type_init_exception_hash)
277 ex = (MonoException *)mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
278 mono_domain_unlock (domain);
281 if (klass->name_space && *klass->name_space)
282 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
284 full_name = g_strdup (klass->name);
285 ex = mono_get_exception_type_initialization_checked (full_name, NULL, &error);
287 return_val_if_nok (&error, NULL);
294 * mono_runtime_class_init:
295 * @vtable: vtable that needs to be initialized
297 * This routine calls the class constructor for @vtable.
300 mono_runtime_class_init (MonoVTable *vtable)
302 MONO_REQ_GC_UNSAFE_MODE;
305 mono_runtime_class_init_full (vtable, &error);
306 mono_error_assert_ok (&error);
310 * mono_runtime_class_init_full:
311 * @vtable that neeeds to be initialized
312 * @error set on error
314 * returns TRUE if class constructor .cctor has been initialized successfully, or FALSE otherwise and sets @error.
318 mono_runtime_class_init_full (MonoVTable *vtable, MonoError *error)
320 MONO_REQ_GC_UNSAFE_MODE;
322 MonoMethod *method = NULL;
325 MonoDomain *domain = vtable->domain;
326 TypeInitializationLock *lock;
327 MonoNativeThreadId tid;
328 int do_initialization = 0;
329 MonoDomain *last_domain = NULL;
331 mono_error_init (error);
333 if (vtable->initialized)
336 klass = vtable->klass;
338 if (!klass->image->checked_module_cctor) {
339 mono_image_check_for_module_cctor (klass->image);
340 if (klass->image->has_module_cctor) {
341 MonoClass *module_klass;
342 MonoVTable *module_vtable;
344 module_klass = mono_class_get_checked (klass->image, MONO_TOKEN_TYPE_DEF | 1, error);
349 module_vtable = mono_class_vtable_full (vtable->domain, module_klass, error);
352 if (!mono_runtime_class_init_full (module_vtable, error))
356 method = mono_class_get_cctor (klass);
358 vtable->initialized = 1;
362 tid = mono_native_thread_id_get ();
364 mono_type_initialization_lock ();
365 /* double check... */
366 if (vtable->initialized) {
367 mono_type_initialization_unlock ();
370 if (vtable->init_failed) {
371 mono_type_initialization_unlock ();
373 /* The type initialization already failed once, rethrow the same exception */
374 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
377 lock = (TypeInitializationLock *)g_hash_table_lookup (type_initialization_hash, vtable);
379 /* This thread will get to do the initialization */
380 if (mono_domain_get () != domain) {
381 /* Transfer into the target domain */
382 last_domain = mono_domain_get ();
383 if (!mono_domain_set (domain, FALSE)) {
384 vtable->initialized = 1;
385 mono_type_initialization_unlock ();
386 mono_error_set_exception_instance (error, mono_get_exception_appdomain_unloaded ());
390 lock = (TypeInitializationLock *)g_malloc (sizeof (TypeInitializationLock));
391 mono_coop_mutex_init_recursive (&lock->initialization_section);
392 lock->initializing_tid = tid;
393 lock->waiting_count = 1;
395 /* grab the vtable lock while this thread still owns type_initialization_section */
396 /* This is why type_initialization_lock needs to enter blocking mode */
397 mono_type_init_lock (lock);
398 g_hash_table_insert (type_initialization_hash, vtable, lock);
399 do_initialization = 1;
402 TypeInitializationLock *pending_lock;
404 if (mono_native_thread_id_equals (lock->initializing_tid, tid) || lock->done) {
405 mono_type_initialization_unlock ();
408 /* see if the thread doing the initialization is already blocked on this thread */
409 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (lock->initializing_tid));
410 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
411 if (mono_native_thread_id_equals (pending_lock->initializing_tid, tid)) {
412 if (!pending_lock->done) {
413 mono_type_initialization_unlock ();
416 /* the thread doing the initialization is blocked on this thread,
417 but on a lock that has already been freed. It just hasn't got
422 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (pending_lock->initializing_tid));
424 ++lock->waiting_count;
425 /* record the fact that we are waiting on the initializing thread */
426 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
428 mono_type_initialization_unlock ();
430 if (do_initialization) {
431 MonoException *exc = NULL;
432 mono_runtime_try_invoke (method, NULL, NULL, (MonoObject**) &exc, error);
433 if (exc != NULL && mono_error_ok (error)) {
434 mono_error_set_exception_instance (error, exc);
437 /* If the initialization failed, mark the class as unusable. */
438 /* Avoid infinite loops */
439 if (!(mono_error_ok(error) ||
440 (klass->image == mono_defaults.corlib &&
441 !strcmp (klass->name_space, "System") &&
442 !strcmp (klass->name, "TypeInitializationException")))) {
443 vtable->init_failed = 1;
445 if (klass->name_space && *klass->name_space)
446 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
448 full_name = g_strdup (klass->name);
450 MonoException *exc_to_throw = mono_get_exception_type_initialization_checked (full_name, exc, error);
452 return_val_if_nok (error, FALSE);
454 mono_error_set_exception_instance (error, exc_to_throw);
456 MonoException *exc_to_store = mono_error_convert_to_exception (error);
457 /* What we really want to do here is clone the error object and store one copy in the
458 * domain's exception hash and use the other one to error out here. */
459 mono_error_set_exception_instance (error, exc_to_store);
461 * Store the exception object so it could be thrown on subsequent
464 mono_domain_lock (domain);
465 if (!domain->type_init_exception_hash)
466 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");
467 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_store);
468 mono_domain_unlock (domain);
472 mono_domain_set (last_domain, TRUE);
474 mono_type_init_unlock (lock);
476 /* this just blocks until the initializing thread is done */
477 mono_type_init_lock (lock);
478 mono_type_init_unlock (lock);
481 mono_type_initialization_lock ();
482 if (!mono_native_thread_id_equals (lock->initializing_tid, tid))
483 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
484 --lock->waiting_count;
485 if (lock->waiting_count == 0) {
486 mono_coop_mutex_destroy (&lock->initialization_section);
487 g_hash_table_remove (type_initialization_hash, vtable);
490 mono_memory_barrier ();
491 if (!vtable->init_failed)
492 vtable->initialized = 1;
493 mono_type_initialization_unlock ();
495 if (vtable->init_failed) {
496 /* Either we were the initializing thread or we waited for the initialization */
497 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
504 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
506 MONO_REQ_GC_NEUTRAL_MODE;
508 MonoVTable *vtable = (MonoVTable*)key;
510 TypeInitializationLock *lock = (TypeInitializationLock*) value;
511 if (mono_native_thread_id_equals (lock->initializing_tid, MONO_UINT_TO_NATIVE_THREAD_ID (GPOINTER_TO_UINT (user))) && !lock->done) {
514 * Have to set this since it cannot be set by the normal code in
515 * mono_runtime_class_init (). In this case, the exception object is not stored,
516 * and get_type_init_exception_for_class () needs to be aware of this.
518 vtable->init_failed = 1;
519 mono_type_init_unlock (lock);
520 --lock->waiting_count;
521 if (lock->waiting_count == 0) {
522 mono_coop_mutex_destroy (&lock->initialization_section);
531 mono_release_type_locks (MonoInternalThread *thread)
533 MONO_REQ_GC_UNSAFE_MODE;
535 mono_type_initialization_lock ();
536 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, GUINT_TO_POINTER (thread->tid));
537 mono_type_initialization_unlock ();
541 default_trampoline (MonoMethod *method)
547 default_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
549 g_assert_not_reached ();
554 #ifndef DISABLE_REMOTING
557 default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target)
559 g_error ("remoting not installed");
563 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
567 default_delegate_trampoline (MonoDomain *domain, MonoClass *klass)
569 g_assert_not_reached ();
573 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
574 static MonoImtThunkBuilder imt_thunk_builder;
575 static gboolean always_build_imt_thunks;
577 #if (MONO_IMT_SIZE > 32)
578 #error "MONO_IMT_SIZE cannot be larger than 32"
582 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
584 memcpy (&callbacks, cbs, sizeof (*cbs));
587 MonoRuntimeCallbacks*
588 mono_get_runtime_callbacks (void)
593 #ifndef DISABLE_REMOTING
595 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
597 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
602 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
604 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
608 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
609 imt_thunk_builder = func;
613 mono_set_always_build_imt_thunks (gboolean value)
615 always_build_imt_thunks = value;
619 * mono_compile_method:
620 * @method: The method to compile.
622 * This JIT-compiles the method, and returns the pointer to the native code
626 mono_compile_method (MonoMethod *method)
631 MONO_REQ_GC_NEUTRAL_MODE
633 if (!callbacks.compile_method) {
634 g_error ("compile method called on uninitialized runtime");
637 res = callbacks.compile_method (method, &error);
638 if (!mono_error_ok (&error))
639 mono_error_raise_exception (&error);
644 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
649 MONO_REQ_GC_NEUTRAL_MODE;
651 res = callbacks.create_jump_trampoline (domain, method, add_sync_wrapper, &error);
652 if (!mono_error_ok (&error))
653 mono_error_raise_exception (&error); /* FIXME: Don't raise here */
658 mono_runtime_create_delegate_trampoline (MonoClass *klass)
660 MONO_REQ_GC_NEUTRAL_MODE
662 return arch_create_delegate_trampoline (mono_domain_get (), klass);
665 static MonoFreeMethodFunc default_mono_free_method = NULL;
668 * mono_install_free_method:
669 * @func: pointer to the MonoFreeMethodFunc used to release a method
671 * This is an internal VM routine, it is used for the engines to
672 * register a handler to release the resources associated with a method.
674 * Methods are freed when no more references to the delegate that holds
678 mono_install_free_method (MonoFreeMethodFunc func)
680 default_mono_free_method = func;
684 * mono_runtime_free_method:
685 * @domain; domain where the method is hosted
686 * @method: method to release
688 * This routine is invoked to free the resources associated with
689 * a method that has been JIT compiled. This is used to discard
690 * methods that were used only temporarily (for example, used in marshalling)
694 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
696 MONO_REQ_GC_NEUTRAL_MODE
698 if (default_mono_free_method != NULL)
699 default_mono_free_method (domain, method);
701 mono_method_clear_object (domain, method);
703 mono_free_method (method);
707 * The vtables in the root appdomain are assumed to be reachable by other
708 * roots, and we don't use typed allocation in the other domains.
711 /* The sync block is no longer a GC pointer */
712 #define GC_HEADER_BITMAP (0)
714 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
717 compute_class_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
719 MONO_REQ_GC_NEUTRAL_MODE;
721 MonoClassField *field;
727 max_size = mono_class_data_size (klass) / sizeof (gpointer);
729 max_size = klass->instance_size / sizeof (gpointer);
730 if (max_size > size) {
731 g_assert (offset <= 0);
732 bitmap = (gsize *)g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
737 /*An Ephemeron cannot be marked by sgen*/
738 if (!static_fields && klass->image == mono_defaults.corlib && !strcmp ("Ephemeron", klass->name)) {
740 memset (bitmap, 0, size / 8);
745 for (p = klass; p != NULL; p = p->parent) {
746 gpointer iter = NULL;
747 while ((field = mono_class_get_fields (p, &iter))) {
751 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
753 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
756 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
759 /* FIXME: should not happen, flag as type load error */
760 if (field->type->byref)
763 if (static_fields && field->offset == -1)
767 pos = field->offset / sizeof (gpointer);
770 type = mono_type_get_underlying_type (field->type);
771 switch (type->type) {
774 case MONO_TYPE_FNPTR:
776 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
781 if (klass->image != mono_defaults.corlib)
784 case MONO_TYPE_STRING:
785 case MONO_TYPE_SZARRAY:
786 case MONO_TYPE_CLASS:
787 case MONO_TYPE_OBJECT:
788 case MONO_TYPE_ARRAY:
789 g_assert ((field->offset % sizeof(gpointer)) == 0);
791 g_assert (pos < size || pos <= max_size);
792 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
793 *max_set = MAX (*max_set, pos);
795 case MONO_TYPE_GENERICINST:
796 if (!mono_type_generic_inst_is_valuetype (type)) {
797 g_assert ((field->offset % sizeof(gpointer)) == 0);
799 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
800 *max_set = MAX (*max_set, pos);
805 case MONO_TYPE_VALUETYPE: {
806 MonoClass *fclass = mono_class_from_mono_type (field->type);
807 if (fclass->has_references) {
808 /* remove the object header */
809 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
823 case MONO_TYPE_BOOLEAN:
827 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
838 * mono_class_compute_bitmap:
840 * Mono internal function to compute a bitmap of reference fields in a class.
843 mono_class_compute_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
845 MONO_REQ_GC_NEUTRAL_MODE;
847 return compute_class_bitmap (klass, bitmap, size, offset, max_set, static_fields);
852 * similar to the above, but sets the bits in the bitmap for any non-ref field
853 * and ignores static fields
856 compute_class_non_ref_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset)
858 MonoClassField *field;
863 max_size = class->instance_size / sizeof (gpointer);
864 if (max_size >= size) {
865 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
868 for (p = class; p != NULL; p = p->parent) {
869 gpointer iter = NULL;
870 while ((field = mono_class_get_fields (p, &iter))) {
873 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
875 /* FIXME: should not happen, flag as type load error */
876 if (field->type->byref)
879 pos = field->offset / sizeof (gpointer);
882 type = mono_type_get_underlying_type (field->type);
883 switch (type->type) {
884 #if SIZEOF_VOID_P == 8
888 case MONO_TYPE_FNPTR:
893 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
894 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
895 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
898 #if SIZEOF_VOID_P == 4
902 case MONO_TYPE_FNPTR:
907 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
908 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
909 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
915 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
916 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
917 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
920 case MONO_TYPE_BOOLEAN:
923 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
925 case MONO_TYPE_STRING:
926 case MONO_TYPE_SZARRAY:
927 case MONO_TYPE_CLASS:
928 case MONO_TYPE_OBJECT:
929 case MONO_TYPE_ARRAY:
931 case MONO_TYPE_GENERICINST:
932 if (!mono_type_generic_inst_is_valuetype (type)) {
937 case MONO_TYPE_VALUETYPE: {
938 MonoClass *fclass = mono_class_from_mono_type (field->type);
939 /* remove the object header */
940 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
944 g_assert_not_reached ();
953 * mono_class_insecure_overlapping:
954 * check if a class with explicit layout has references and non-references
955 * fields overlapping.
957 * Returns: TRUE if it is insecure to load the type.
960 mono_class_insecure_overlapping (MonoClass *klass)
964 gsize default_bitmap [4] = {0};
966 gsize default_nrbitmap [4] = {0};
967 int i, insecure = FALSE;
970 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
971 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
973 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
974 int idx = i % (sizeof (bitmap [0]) * 8);
975 if (bitmap [idx] & nrbitmap [idx]) {
980 if (bitmap != default_bitmap)
982 if (nrbitmap != default_nrbitmap)
985 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
993 ves_icall_string_alloc (int length)
996 MonoString *str = mono_string_new_size_checked (mono_domain_get (), length, &error);
997 mono_error_raise_exception (&error);
1003 mono_class_compute_gc_descriptor (MonoClass *klass)
1005 MONO_REQ_GC_NEUTRAL_MODE;
1009 gsize default_bitmap [4] = {0};
1010 static gboolean gcj_inited = FALSE;
1013 mono_loader_lock ();
1015 mono_register_jit_icall (ves_icall_object_new_fast, "ves_icall_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
1016 mono_register_jit_icall (ves_icall_string_alloc, "ves_icall_string_alloc", mono_create_icall_signature ("object int"), FALSE);
1019 mono_loader_unlock ();
1023 mono_class_init (klass);
1025 if (klass->gc_descr_inited)
1028 klass->gc_descr_inited = TRUE;
1029 klass->gc_descr = MONO_GC_DESCRIPTOR_NULL;
1031 bitmap = default_bitmap;
1032 if (klass == mono_defaults.string_class) {
1033 klass->gc_descr = mono_gc_make_descr_for_string (bitmap, 2);
1034 } else if (klass->rank) {
1035 mono_class_compute_gc_descriptor (klass->element_class);
1036 if (MONO_TYPE_IS_REFERENCE (&klass->element_class->byval_arg)) {
1038 klass->gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
1039 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1040 class->name_space, class->name);*/
1042 /* remove the object header */
1043 bitmap = compute_class_bitmap (klass->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
1044 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));
1045 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1046 class->name_space, class->name);*/
1047 if (bitmap != default_bitmap)
1051 /*static int count = 0;
1054 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1055 klass->gc_descr = mono_gc_make_descr_for_object (bitmap, max_set + 1, klass->instance_size);
1057 if (class->gc_descr == MONO_GC_DESCRIPTOR_NULL)
1058 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
1060 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
1061 if (bitmap != default_bitmap)
1067 * field_is_special_static:
1068 * @fklass: The MonoClass to look up.
1069 * @field: The MonoClassField describing the field.
1071 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1072 * SPECIAL_STATIC_NONE otherwise.
1075 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1077 MONO_REQ_GC_NEUTRAL_MODE;
1080 MonoCustomAttrInfo *ainfo;
1082 ainfo = mono_custom_attrs_from_field_checked (fklass, field, &error);
1083 mono_error_cleanup (&error); /* FIXME don't swallow the error? */
1086 for (i = 0; i < ainfo->num_attrs; ++i) {
1087 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1088 if (klass->image == mono_defaults.corlib) {
1089 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1090 mono_custom_attrs_free (ainfo);
1091 return SPECIAL_STATIC_THREAD;
1093 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1094 mono_custom_attrs_free (ainfo);
1095 return SPECIAL_STATIC_CONTEXT;
1099 mono_custom_attrs_free (ainfo);
1100 return SPECIAL_STATIC_NONE;
1103 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1104 #define mix(a,b,c) { \
1105 a -= c; a ^= rot(c, 4); c += b; \
1106 b -= a; b ^= rot(a, 6); a += c; \
1107 c -= b; c ^= rot(b, 8); b += a; \
1108 a -= c; a ^= rot(c,16); c += b; \
1109 b -= a; b ^= rot(a,19); a += c; \
1110 c -= b; c ^= rot(b, 4); b += a; \
1112 #define final(a,b,c) { \
1113 c ^= b; c -= rot(b,14); \
1114 a ^= c; a -= rot(c,11); \
1115 b ^= a; b -= rot(a,25); \
1116 c ^= b; c -= rot(b,16); \
1117 a ^= c; a -= rot(c,4); \
1118 b ^= a; b -= rot(a,14); \
1119 c ^= b; c -= rot(b,24); \
1123 * mono_method_get_imt_slot:
1125 * The IMT slot is embedded into AOTed code, so this must return the same value
1126 * for the same method across all executions. This means:
1127 * - pointers shouldn't be used as hash values.
1128 * - mono_metadata_str_hash () should be used for hashing strings.
1131 mono_method_get_imt_slot (MonoMethod *method)
1133 MONO_REQ_GC_NEUTRAL_MODE;
1135 MonoMethodSignature *sig;
1137 guint32 *hashes_start, *hashes;
1141 /* This can be used to stress tests the collision code */
1145 * We do this to simplify generic sharing. It will hurt
1146 * performance in cases where a class implements two different
1147 * instantiations of the same generic interface.
1148 * The code in build_imt_slots () depends on this.
1150 if (method->is_inflated)
1151 method = ((MonoMethodInflated*)method)->declaring;
1153 sig = mono_method_signature (method);
1154 hashes_count = sig->param_count + 4;
1155 hashes_start = (guint32 *)malloc (hashes_count * sizeof (guint32));
1156 hashes = hashes_start;
1158 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1159 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1160 method->klass->name_space, method->klass->name, method->name);
1163 /* Initialize hashes */
1164 hashes [0] = mono_metadata_str_hash (method->klass->name);
1165 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1166 hashes [2] = mono_metadata_str_hash (method->name);
1167 hashes [3] = mono_metadata_type_hash (sig->ret);
1168 for (i = 0; i < sig->param_count; i++) {
1169 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1172 /* Setup internal state */
1173 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1175 /* Handle most of the hashes */
1176 while (hashes_count > 3) {
1185 /* Handle the last 3 hashes (all the case statements fall through) */
1186 switch (hashes_count) {
1187 case 3 : c += hashes [2];
1188 case 2 : b += hashes [1];
1189 case 1 : a += hashes [0];
1191 case 0: /* nothing left to add */
1195 free (hashes_start);
1196 /* Report the result */
1197 return c % MONO_IMT_SIZE;
1206 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1207 MONO_REQ_GC_NEUTRAL_MODE;
1209 guint32 imt_slot = mono_method_get_imt_slot (method);
1210 MonoImtBuilderEntry *entry;
1212 if (slot_num >= 0 && imt_slot != slot_num) {
1213 /* we build just a single imt slot and this is not it */
1217 entry = (MonoImtBuilderEntry *)g_malloc0 (sizeof (MonoImtBuilderEntry));
1218 entry->key = method;
1219 entry->value.vtable_slot = vtable_slot;
1220 entry->next = imt_builder [imt_slot];
1221 if (imt_builder [imt_slot] != NULL) {
1222 entry->children = imt_builder [imt_slot]->children + 1;
1223 if (entry->children == 1) {
1224 mono_stats.imt_slots_with_collisions++;
1225 *imt_collisions_bitmap |= (1 << imt_slot);
1228 entry->children = 0;
1229 mono_stats.imt_used_slots++;
1231 imt_builder [imt_slot] = entry;
1234 char *method_name = mono_method_full_name (method, TRUE);
1235 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1236 method, method_name, imt_slot, vtable_slot, entry->children);
1237 g_free (method_name);
1244 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1246 MonoMethod *method = e->key;
1247 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1251 method->klass->name_space,
1252 method->klass->name,
1255 printf (" * %s: NULL\n", message);
1261 compare_imt_builder_entries (const void *p1, const void *p2) {
1262 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1263 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1265 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1269 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1271 MONO_REQ_GC_NEUTRAL_MODE;
1273 int count = end - start;
1274 int chunk_start = out_array->len;
1277 for (i = start; i < end; ++i) {
1278 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1279 item->key = sorted_array [i]->key;
1280 item->value = sorted_array [i]->value;
1281 item->has_target_code = sorted_array [i]->has_target_code;
1282 item->is_equals = TRUE;
1284 item->check_target_idx = out_array->len + 1;
1286 item->check_target_idx = 0;
1287 g_ptr_array_add (out_array, item);
1290 int middle = start + count / 2;
1291 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1293 item->key = sorted_array [middle]->key;
1294 item->is_equals = FALSE;
1295 g_ptr_array_add (out_array, item);
1296 imt_emit_ir (sorted_array, start, middle, out_array);
1297 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1303 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1304 MONO_REQ_GC_NEUTRAL_MODE;
1306 int number_of_entries = entries->children + 1;
1307 MonoImtBuilderEntry **sorted_array = (MonoImtBuilderEntry **)malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1308 GPtrArray *result = g_ptr_array_new ();
1309 MonoImtBuilderEntry *current_entry;
1312 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1313 sorted_array [i] = current_entry;
1315 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1317 /*for (i = 0; i < number_of_entries; i++) {
1318 print_imt_entry (" sorted array:", sorted_array [i], i);
1321 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1323 free (sorted_array);
1328 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1330 MONO_REQ_GC_NEUTRAL_MODE;
1332 if (imt_builder_entry != NULL) {
1333 if (imt_builder_entry->children == 0 && !fail_tramp && !always_build_imt_thunks) {
1334 /* No collision, return the vtable slot contents */
1335 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1337 /* Collision, build the thunk */
1338 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1341 result = imt_thunk_builder (vtable, domain,
1342 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1343 for (i = 0; i < imt_ir->len; ++i)
1344 g_free (g_ptr_array_index (imt_ir, i));
1345 g_ptr_array_free (imt_ir, TRUE);
1357 static MonoImtBuilderEntry*
1358 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1361 * LOCKING: requires the loader and domain locks.
1365 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1367 MONO_REQ_GC_NEUTRAL_MODE;
1371 guint32 imt_collisions_bitmap = 0;
1372 MonoImtBuilderEntry **imt_builder = (MonoImtBuilderEntry **)calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1373 int method_count = 0;
1374 gboolean record_method_count_for_max_collisions = FALSE;
1375 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1378 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1380 for (i = 0; i < klass->interface_offsets_count; ++i) {
1381 MonoClass *iface = klass->interfaces_packed [i];
1382 int interface_offset = klass->interface_offsets_packed [i];
1383 int method_slot_in_interface, vt_slot;
1385 if (mono_class_has_variant_generic_params (iface))
1386 has_variant_iface = TRUE;
1388 mono_class_setup_methods (iface);
1389 vt_slot = interface_offset;
1390 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1393 if (slot_num >= 0 && iface->is_inflated) {
1395 * The imt slot of the method is the same as for its declaring method,
1396 * see the comment in mono_method_get_imt_slot (), so we can
1397 * avoid inflating methods which will be discarded by
1398 * add_imt_builder_entry anyway.
1400 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1401 if (mono_method_get_imt_slot (method) != slot_num) {
1406 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1407 if (method->is_generic) {
1408 has_generic_virtual = TRUE;
1413 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1414 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1419 if (extra_interfaces) {
1420 int interface_offset = klass->vtable_size;
1422 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1423 MonoClass* iface = (MonoClass *)list_item->data;
1424 int method_slot_in_interface;
1425 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1426 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1428 if (method->is_generic)
1429 has_generic_virtual = TRUE;
1430 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1432 interface_offset += iface->method.count;
1435 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1436 /* overwrite the imt slot only if we're building all the entries or if
1437 * we're building this specific one
1439 if (slot_num < 0 || i == slot_num) {
1440 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1443 if (imt_builder [i]) {
1444 MonoImtBuilderEntry *entry;
1446 /* Link entries with imt_builder [i] */
1447 for (entry = entries; entry->next; entry = entry->next) {
1449 MonoMethod *method = (MonoMethod*)entry->key;
1450 char *method_name = mono_method_full_name (method, TRUE);
1451 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1452 g_free (method_name);
1455 entry->next = imt_builder [i];
1456 entries->children += imt_builder [i]->children + 1;
1458 imt_builder [i] = entries;
1461 if (has_generic_virtual || has_variant_iface) {
1463 * There might be collisions later when the the thunk is expanded.
1465 imt_collisions_bitmap |= (1 << i);
1468 * The IMT thunk might be called with an instance of one of the
1469 * generic virtual methods, so has to fallback to the IMT trampoline.
1471 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline (vt, i));
1473 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1476 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1480 if (imt_builder [i] != NULL) {
1481 int methods_in_slot = imt_builder [i]->children + 1;
1482 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1483 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1484 record_method_count_for_max_collisions = TRUE;
1486 method_count += methods_in_slot;
1490 mono_stats.imt_number_of_methods += method_count;
1491 if (record_method_count_for_max_collisions) {
1492 mono_stats.imt_method_count_when_max_collisions = method_count;
1495 for (i = 0; i < MONO_IMT_SIZE; i++) {
1496 MonoImtBuilderEntry* entry = imt_builder [i];
1497 while (entry != NULL) {
1498 MonoImtBuilderEntry* next = entry->next;
1504 /* we OR the bitmap since we may build just a single imt slot at a time */
1505 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1509 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1510 MONO_REQ_GC_NEUTRAL_MODE;
1512 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1516 * mono_vtable_build_imt_slot:
1517 * @vtable: virtual object table struct
1518 * @imt_slot: slot in the IMT table
1520 * Fill the given @imt_slot in the IMT table of @vtable with
1521 * a trampoline or a thunk for the case of collisions.
1522 * This is part of the internal mono API.
1524 * LOCKING: Take the domain lock.
1527 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1529 MONO_REQ_GC_NEUTRAL_MODE;
1531 gpointer *imt = (gpointer*)vtable;
1532 imt -= MONO_IMT_SIZE;
1533 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1535 /* no support for extra interfaces: the proxy objects will need
1536 * to build the complete IMT
1537 * Update and heck needs to ahppen inside the proper domain lock, as all
1538 * the changes made to a MonoVTable.
1540 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1541 mono_domain_lock (vtable->domain);
1542 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1543 if (!callbacks.imt_entry_inited (vtable, imt_slot))
1544 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1545 mono_domain_unlock (vtable->domain);
1546 mono_loader_unlock ();
1551 * The first two free list entries both belong to the wait list: The
1552 * first entry is the pointer to the head of the list and the second
1553 * entry points to the last element. That way appending and removing
1554 * the first element are both O(1) operations.
1556 #ifdef MONO_SMALL_CONFIG
1557 #define NUM_FREE_LISTS 6
1559 #define NUM_FREE_LISTS 12
1561 #define FIRST_FREE_LIST_SIZE 64
1562 #define MAX_WAIT_LENGTH 50
1563 #define THUNK_THRESHOLD 10
1566 * LOCKING: The domain lock must be held.
1569 init_thunk_free_lists (MonoDomain *domain)
1571 MONO_REQ_GC_NEUTRAL_MODE;
1573 if (domain->thunk_free_lists)
1575 domain->thunk_free_lists = (MonoThunkFreeList **)mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1579 list_index_for_size (int item_size)
1582 int size = FIRST_FREE_LIST_SIZE;
1584 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1593 * mono_method_alloc_generic_virtual_thunk:
1595 * @size: size in bytes
1597 * Allocs size bytes to be used for the code of a generic virtual
1598 * thunk. It's either allocated from the domain's code manager or
1599 * reused from a previously invalidated piece.
1601 * LOCKING: The domain lock must be held.
1604 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1606 MONO_REQ_GC_NEUTRAL_MODE;
1608 static gboolean inited = FALSE;
1609 static int generic_virtual_thunks_size = 0;
1613 MonoThunkFreeList **l;
1615 init_thunk_free_lists (domain);
1617 size += sizeof (guint32);
1618 if (size < sizeof (MonoThunkFreeList))
1619 size = sizeof (MonoThunkFreeList);
1621 i = list_index_for_size (size);
1622 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1623 if ((*l)->size >= size) {
1624 MonoThunkFreeList *item = *l;
1626 return ((guint32*)item) + 1;
1630 /* no suitable item found - search lists of larger sizes */
1631 while (++i < NUM_FREE_LISTS) {
1632 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1635 g_assert (item->size > size);
1636 domain->thunk_free_lists [i] = item->next;
1637 return ((guint32*)item) + 1;
1640 /* still nothing found - allocate it */
1642 mono_counters_register ("Generic virtual thunk bytes",
1643 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1646 generic_virtual_thunks_size += size;
1648 p = (guint32 *)mono_domain_code_reserve (domain, size);
1651 mono_domain_lock (domain);
1652 if (!domain->generic_virtual_thunks)
1653 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1654 g_hash_table_insert (domain->generic_virtual_thunks, p, p);
1655 mono_domain_unlock (domain);
1661 * LOCKING: The domain lock must be held.
1664 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1666 MONO_REQ_GC_NEUTRAL_MODE;
1668 guint32 *p = (guint32 *)code;
1669 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1670 gboolean found = FALSE;
1672 mono_domain_lock (domain);
1673 if (!domain->generic_virtual_thunks)
1674 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1675 if (g_hash_table_lookup (domain->generic_virtual_thunks, l))
1677 mono_domain_unlock (domain);
1680 /* Not allocated by mono_method_alloc_generic_virtual_thunk (), i.e. AOT */
1682 init_thunk_free_lists (domain);
1684 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1685 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1686 int length = item->length;
1689 /* unlink the first item from the wait list */
1690 domain->thunk_free_lists [0] = item->next;
1691 domain->thunk_free_lists [0]->length = length - 1;
1693 i = list_index_for_size (item->size);
1695 /* put it in the free list */
1696 item->next = domain->thunk_free_lists [i];
1697 domain->thunk_free_lists [i] = item;
1701 if (domain->thunk_free_lists [1]) {
1702 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1703 domain->thunk_free_lists [0]->length++;
1705 g_assert (!domain->thunk_free_lists [0]);
1707 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1708 domain->thunk_free_lists [0]->length = 1;
1712 typedef struct _GenericVirtualCase {
1716 struct _GenericVirtualCase *next;
1717 } GenericVirtualCase;
1720 * get_generic_virtual_entries:
1722 * Return IMT entries for the generic virtual method instances and
1723 * variant interface methods for vtable slot
1726 static MonoImtBuilderEntry*
1727 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1729 MONO_REQ_GC_NEUTRAL_MODE;
1731 GenericVirtualCase *list;
1732 MonoImtBuilderEntry *entries;
1734 mono_domain_lock (domain);
1735 if (!domain->generic_virtual_cases)
1736 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1738 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1741 for (; list; list = list->next) {
1742 MonoImtBuilderEntry *entry;
1744 if (list->count < THUNK_THRESHOLD)
1747 entry = g_new0 (MonoImtBuilderEntry, 1);
1748 entry->key = list->method;
1749 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1750 entry->has_target_code = 1;
1752 entry->children = entries->children + 1;
1753 entry->next = entries;
1757 mono_domain_unlock (domain);
1759 /* FIXME: Leaking memory ? */
1764 * mono_method_add_generic_virtual_invocation:
1766 * @vtable_slot: pointer to the vtable slot
1767 * @method: the inflated generic virtual method
1768 * @code: the method's code
1770 * Registers a call via unmanaged code to a generic virtual method
1771 * instantiation or variant interface method. If the number of calls reaches a threshold
1772 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1773 * virtual method thunk.
1776 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1777 gpointer *vtable_slot,
1778 MonoMethod *method, gpointer code)
1780 MONO_REQ_GC_NEUTRAL_MODE;
1782 static gboolean inited = FALSE;
1783 static int num_added = 0;
1785 GenericVirtualCase *gvc, *list;
1786 MonoImtBuilderEntry *entries;
1790 mono_domain_lock (domain);
1791 if (!domain->generic_virtual_cases)
1792 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1794 /* Check whether the case was already added */
1795 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1798 if (gvc->method == method)
1803 /* If not found, make a new one */
1805 gvc = (GenericVirtualCase *)mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1806 gvc->method = method;
1809 gvc->next = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1811 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1814 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1820 if (++gvc->count == THUNK_THRESHOLD) {
1821 gpointer *old_thunk = (void **)*vtable_slot;
1822 gpointer vtable_trampoline = NULL;
1823 gpointer imt_trampoline = NULL;
1825 if ((gpointer)vtable_slot < (gpointer)vtable) {
1826 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1827 int imt_slot = MONO_IMT_SIZE + displacement;
1829 /* Force the rebuild of the thunk at the next call */
1830 imt_trampoline = callbacks.get_imt_trampoline (vtable, imt_slot);
1831 *vtable_slot = imt_trampoline;
1833 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline (vtable, (gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1835 entries = get_generic_virtual_entries (domain, vtable_slot);
1837 sorted = imt_sort_slot_entries (entries);
1839 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1843 MonoImtBuilderEntry *next = entries->next;
1848 for (i = 0; i < sorted->len; ++i)
1849 g_free (g_ptr_array_index (sorted, i));
1850 g_ptr_array_free (sorted, TRUE);
1853 #ifndef __native_client__
1854 /* We don't re-use any thunks as there is a lot of overhead */
1855 /* to deleting and re-using code in Native Client. */
1856 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1857 invalidate_generic_virtual_thunk (domain, old_thunk);
1861 mono_domain_unlock (domain);
1864 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error);
1867 * mono_class_vtable:
1868 * @domain: the application domain
1869 * @class: the class to initialize
1871 * VTables are domain specific because we create domain specific code, and
1872 * they contain the domain specific static class data.
1873 * On failure, NULL is returned, and class->exception_type is set.
1876 mono_class_vtable (MonoDomain *domain, MonoClass *klass)
1879 MonoVTable* vtable = mono_class_vtable_full (domain, klass, &error);
1880 mono_error_cleanup (&error);
1885 * mono_class_vtable_full:
1886 * @domain: the application domain
1887 * @class: the class to initialize
1888 * @error set on failure.
1890 * VTables are domain specific because we create domain specific code, and
1891 * they contain the domain specific static class data.
1894 mono_class_vtable_full (MonoDomain *domain, MonoClass *klass, MonoError *error)
1896 MONO_REQ_GC_UNSAFE_MODE;
1898 MonoClassRuntimeInfo *runtime_info;
1900 mono_error_init (error);
1904 if (mono_class_has_failure (klass)) {
1905 mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (klass));
1909 /* this check can be inlined in jitted code, too */
1910 runtime_info = klass->runtime_info;
1911 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1912 return runtime_info->domain_vtables [domain->domain_id];
1913 return mono_class_create_runtime_vtable (domain, klass, error);
1917 * mono_class_try_get_vtable:
1918 * @domain: the application domain
1919 * @class: the class to initialize
1921 * This function tries to get the associated vtable from @class if
1922 * it was already created.
1925 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *klass)
1927 MONO_REQ_GC_NEUTRAL_MODE;
1929 MonoClassRuntimeInfo *runtime_info;
1933 runtime_info = klass->runtime_info;
1934 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1935 return runtime_info->domain_vtables [domain->domain_id];
1940 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1942 MONO_REQ_GC_NEUTRAL_MODE;
1944 size_t alloc_offset;
1947 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1948 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1949 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1951 if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1952 g_assert ((imt_table_bytes & 7) == 4);
1959 return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1963 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error)
1965 MONO_REQ_GC_UNSAFE_MODE;
1968 MonoClassRuntimeInfo *runtime_info, *old_info;
1969 MonoClassField *field;
1971 int i, vtable_slots;
1972 size_t imt_table_bytes;
1974 guint32 vtable_size, class_size;
1976 gpointer *interface_offsets;
1978 mono_error_init (error);
1980 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1981 mono_domain_lock (domain);
1982 runtime_info = klass->runtime_info;
1983 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1984 mono_domain_unlock (domain);
1985 mono_loader_unlock ();
1986 return runtime_info->domain_vtables [domain->domain_id];
1988 if (!klass->inited || mono_class_has_failure (klass)) {
1989 if (!mono_class_init (klass) || mono_class_has_failure (klass)) {
1990 mono_domain_unlock (domain);
1991 mono_loader_unlock ();
1992 mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (klass));
1997 /* Array types require that their element type be valid*/
1998 if (klass->byval_arg.type == MONO_TYPE_ARRAY || klass->byval_arg.type == MONO_TYPE_SZARRAY) {
1999 MonoClass *element_class = klass->element_class;
2000 if (!element_class->inited)
2001 mono_class_init (element_class);
2003 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
2004 if (!mono_class_has_failure (element_class) && !element_class->vtable_size)
2005 mono_class_setup_vtable (element_class);
2007 if (mono_class_has_failure (element_class)) {
2008 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
2009 if (!mono_class_has_failure (klass))
2010 mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
2011 mono_domain_unlock (domain);
2012 mono_loader_unlock ();
2013 mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (klass));
2019 * For some classes, mono_class_init () already computed klass->vtable_size, and
2020 * that is all that is needed because of the vtable trampolines.
2022 if (!klass->vtable_size)
2023 mono_class_setup_vtable (klass);
2025 if (klass->generic_class && !klass->vtable)
2026 mono_class_check_vtable_constraints (klass, NULL);
2028 /* Initialize klass->has_finalize */
2029 mono_class_has_finalizer (klass);
2031 if (mono_class_has_failure (klass)) {
2032 mono_domain_unlock (domain);
2033 mono_loader_unlock ();
2034 mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (klass));
2038 vtable_slots = klass->vtable_size;
2039 /* we add an additional vtable slot to store the pointer to static field data only when needed */
2040 class_size = mono_class_data_size (klass);
2044 if (klass->interface_offsets_count) {
2045 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
2046 mono_stats.imt_number_of_tables++;
2047 mono_stats.imt_tables_size += imt_table_bytes;
2049 imt_table_bytes = 0;
2052 vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
2054 mono_stats.used_class_count++;
2055 mono_stats.class_vtable_size += vtable_size;
2057 interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
2058 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2059 g_assert (!((gsize)vt & 7));
2062 vt->rank = klass->rank;
2063 vt->domain = domain;
2065 mono_class_compute_gc_descriptor (klass);
2067 * We can't use typed allocation in the non-root domains, since the
2068 * collector needs the GC descriptor stored in the vtable even after
2069 * the mempool containing the vtable is destroyed when the domain is
2070 * unloaded. An alternative might be to allocate vtables in the GC
2071 * heap, but this does not seem to work (it leads to crashes inside
2072 * libgc). If that approach is tried, two gc descriptors need to be
2073 * allocated for each class: one for the root domain, and one for all
2074 * other domains. The second descriptor should contain a bit for the
2075 * vtable field in MonoObject, since we can no longer assume the
2076 * vtable is reachable by other roots after the appdomain is unloaded.
2078 #ifdef HAVE_BOEHM_GC
2079 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
2080 vt->gc_descr = MONO_GC_DESCRIPTOR_NULL;
2083 vt->gc_descr = klass->gc_descr;
2085 gc_bits = mono_gc_get_vtable_bits (klass);
2086 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
2088 vt->gc_bits = gc_bits;
2091 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
2092 if (klass->has_static_refs) {
2093 MonoGCDescriptor statics_gc_descr;
2095 gsize default_bitmap [4] = {0};
2098 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
2099 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], klass->name_space, klass->name, class_size);*/
2100 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
2101 vt->vtable [klass->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr, MONO_ROOT_SOURCE_STATIC, "managed static variables");
2102 mono_domain_add_class_static_data (domain, klass, vt->vtable [klass->vtable_size], NULL);
2103 if (bitmap != default_bitmap)
2106 vt->vtable [klass->vtable_size] = mono_domain_alloc0 (domain, class_size);
2108 vt->has_static_fields = TRUE;
2109 mono_stats.class_static_data_size += class_size;
2113 while ((field = mono_class_get_fields (klass, &iter))) {
2114 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2116 if (mono_field_is_deleted (field))
2118 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2119 gint32 special_static = klass->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (klass, field);
2120 if (special_static != SPECIAL_STATIC_NONE) {
2121 guint32 size, offset;
2123 gsize default_bitmap [4] = {0};
2128 if (mono_type_is_reference (field->type)) {
2129 default_bitmap [0] = 1;
2131 bitmap = default_bitmap;
2132 } else if (mono_type_is_struct (field->type)) {
2133 fclass = mono_class_from_mono_type (field->type);
2134 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
2135 numbits = max_set + 1;
2137 default_bitmap [0] = 0;
2139 bitmap = default_bitmap;
2141 size = mono_type_size (field->type, &align);
2142 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
2143 if (!domain->special_static_fields)
2144 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2145 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2146 if (bitmap != default_bitmap)
2149 * This marks the field as special static to speed up the
2150 * checks in mono_field_static_get/set_value ().
2156 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2157 MonoClass *fklass = mono_class_from_mono_type (field->type);
2158 const char *data = mono_field_get_data (field);
2160 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2161 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2162 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2165 if (fklass->valuetype) {
2166 memcpy (t, data, mono_class_value_size (fklass, NULL));
2168 /* it's a pointer type: add check */
2169 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2176 vt->max_interface_id = klass->max_interface_id;
2177 vt->interface_bitmap = klass->interface_bitmap;
2179 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2180 // class->name, klass->interface_offsets_count);
2182 /* Initialize vtable */
2183 if (callbacks.get_vtable_trampoline) {
2184 // This also covers the AOT case
2185 for (i = 0; i < klass->vtable_size; ++i) {
2186 vt->vtable [i] = callbacks.get_vtable_trampoline (vt, i);
2189 mono_class_setup_vtable (klass);
2191 for (i = 0; i < klass->vtable_size; ++i) {
2194 cm = klass->vtable [i];
2196 vt->vtable [i] = callbacks.create_jit_trampoline (domain, cm, error);
2197 if (!is_ok (error)) {
2198 mono_domain_unlock (domain);
2199 mono_loader_unlock ();
2206 if (imt_table_bytes) {
2207 /* Now that the vtable is full, we can actually fill up the IMT */
2208 for (i = 0; i < MONO_IMT_SIZE; ++i)
2209 interface_offsets [i] = callbacks.get_imt_trampoline (vt, i);
2213 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2214 * re-acquire them and check if another thread has created the vtable in the meantime.
2216 /* Special case System.MonoType to avoid infinite recursion */
2217 if (klass != mono_defaults.monotype_class) {
2218 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2219 if (!is_ok (error)) {
2220 mono_domain_unlock (domain);
2221 mono_loader_unlock ();
2225 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.monotype_class)
2226 /* This is unregistered in
2227 unregister_vtable_reflection_type() in
2229 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2232 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (klass));
2234 /* class_vtable_array keeps an array of created vtables
2236 g_ptr_array_add (domain->class_vtable_array, vt);
2237 /* klass->runtime_info is protected by the loader lock, both when
2238 * it it enlarged and when it is stored info.
2242 * Store the vtable in klass->runtime_info.
2243 * klass->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2245 mono_memory_barrier ();
2247 old_info = klass->runtime_info;
2248 if (old_info && old_info->max_domain >= domain->domain_id) {
2249 /* someone already created a large enough runtime info */
2250 old_info->domain_vtables [domain->domain_id] = vt;
2252 int new_size = domain->domain_id;
2254 new_size = MAX (new_size, old_info->max_domain);
2256 /* make the new size a power of two */
2258 while (new_size > i)
2261 /* this is a bounded memory retention issue: may want to
2262 * handle it differently when we'll have a rcu-like system.
2264 runtime_info = (MonoClassRuntimeInfo *)mono_image_alloc0 (klass->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2265 runtime_info->max_domain = new_size - 1;
2266 /* copy the stuff from the older info */
2268 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2270 runtime_info->domain_vtables [domain->domain_id] = vt;
2272 mono_memory_barrier ();
2273 klass->runtime_info = runtime_info;
2276 if (klass == mono_defaults.monotype_class) {
2277 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2278 if (!is_ok (error)) {
2279 mono_domain_unlock (domain);
2280 mono_loader_unlock ();
2284 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.monotype_class)
2285 /* This is unregistered in
2286 unregister_vtable_reflection_type() in
2288 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2291 mono_domain_unlock (domain);
2292 mono_loader_unlock ();
2294 /* make sure the parent is initialized */
2295 /*FIXME shouldn't this fail the current type?*/
2297 mono_class_vtable_full (domain, klass->parent, error);
2302 #ifndef DISABLE_REMOTING
2304 * mono_class_proxy_vtable:
2305 * @domain: the application domain
2306 * @remove_class: the remote class
2308 * Creates a vtable for transparent proxies. It is basically
2309 * a copy of the real vtable of the class wrapped in @remote_class,
2310 * but all function pointers invoke the remoting functions, and
2311 * vtable->klass points to the transparent proxy class, and not to @class.
2314 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2316 MONO_REQ_GC_UNSAFE_MODE;
2319 MonoVTable *vt, *pvt;
2320 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2322 GSList *extra_interfaces = NULL;
2323 MonoClass *klass = remote_class->proxy_class;
2324 gpointer *interface_offsets;
2327 size_t imt_table_bytes;
2329 #ifdef COMPRESSED_INTERFACE_BITMAP
2333 vt = mono_class_vtable (domain, klass);
2334 g_assert (vt); /*FIXME property handle failure*/
2335 max_interface_id = vt->max_interface_id;
2337 /* Calculate vtable space for extra interfaces */
2338 for (j = 0; j < remote_class->interface_count; j++) {
2339 MonoClass* iclass = remote_class->interfaces[j];
2343 /*FIXME test for interfaces with variant generic arguments*/
2344 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, iclass->interface_id))
2345 continue; /* interface implemented by the class */
2346 if (g_slist_find (extra_interfaces, iclass))
2349 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2351 method_count = mono_class_num_methods (iclass);
2353 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2354 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2356 for (i = 0; i < ifaces->len; ++i) {
2357 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2358 /*FIXME test for interfaces with variant generic arguments*/
2359 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, ic->interface_id))
2360 continue; /* interface implemented by the class */
2361 if (g_slist_find (extra_interfaces, ic))
2363 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2364 method_count += mono_class_num_methods (ic);
2366 g_ptr_array_free (ifaces, TRUE);
2369 extra_interface_vtsize += method_count * sizeof (gpointer);
2370 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2373 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2374 mono_stats.imt_number_of_tables++;
2375 mono_stats.imt_tables_size += imt_table_bytes;
2377 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer);
2379 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2381 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2382 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2383 g_assert (!((gsize)pvt & 7));
2385 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer));
2387 pvt->klass = mono_defaults.transparent_proxy_class;
2388 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2389 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2391 /* initialize vtable */
2392 mono_class_setup_vtable (klass);
2393 for (i = 0; i < klass->vtable_size; ++i) {
2396 if ((cm = klass->vtable [i]))
2397 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2399 pvt->vtable [i] = NULL;
2402 if (klass->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2403 /* create trampolines for abstract methods */
2404 for (k = klass; k; k = k->parent) {
2406 gpointer iter = NULL;
2407 while ((m = mono_class_get_methods (k, &iter)))
2408 if (!pvt->vtable [m->slot])
2409 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2413 pvt->max_interface_id = max_interface_id;
2414 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2415 #ifdef COMPRESSED_INTERFACE_BITMAP
2416 bitmap = (uint8_t *)g_malloc0 (bsize);
2418 bitmap = (uint8_t *)mono_domain_alloc0 (domain, bsize);
2421 for (i = 0; i < klass->interface_offsets_count; ++i) {
2422 int interface_id = klass->interfaces_packed [i]->interface_id;
2423 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2426 if (extra_interfaces) {
2427 int slot = klass->vtable_size;
2433 /* Create trampolines for the methods of the interfaces */
2434 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2435 interf = (MonoClass *)list_item->data;
2437 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2441 while ((cm = mono_class_get_methods (interf, &iter)))
2442 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2444 slot += mono_class_num_methods (interf);
2448 /* Now that the vtable is full, we can actually fill up the IMT */
2449 build_imt (klass, pvt, domain, interface_offsets, extra_interfaces);
2450 if (extra_interfaces) {
2451 g_slist_free (extra_interfaces);
2454 #ifdef COMPRESSED_INTERFACE_BITMAP
2455 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2456 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2457 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2460 pvt->interface_bitmap = bitmap;
2465 #endif /* DISABLE_REMOTING */
2468 * mono_class_field_is_special_static:
2470 * Returns whether @field is a thread/context static field.
2473 mono_class_field_is_special_static (MonoClassField *field)
2475 MONO_REQ_GC_NEUTRAL_MODE
2477 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2479 if (mono_field_is_deleted (field))
2481 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2482 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2489 * mono_class_field_get_special_static_type:
2490 * @field: The MonoClassField describing the field.
2492 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2493 * SPECIAL_STATIC_NONE otherwise.
2496 mono_class_field_get_special_static_type (MonoClassField *field)
2498 MONO_REQ_GC_NEUTRAL_MODE
2500 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2501 return SPECIAL_STATIC_NONE;
2502 if (mono_field_is_deleted (field))
2503 return SPECIAL_STATIC_NONE;
2504 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2505 return field_is_special_static (field->parent, field);
2506 return SPECIAL_STATIC_NONE;
2510 * mono_class_has_special_static_fields:
2512 * Returns whenever @klass has any thread/context static fields.
2515 mono_class_has_special_static_fields (MonoClass *klass)
2517 MONO_REQ_GC_NEUTRAL_MODE
2519 MonoClassField *field;
2523 while ((field = mono_class_get_fields (klass, &iter))) {
2524 g_assert (field->parent == klass);
2525 if (mono_class_field_is_special_static (field))
2532 #ifndef DISABLE_REMOTING
2534 * create_remote_class_key:
2535 * Creates an array of pointers that can be used as a hash key for a remote class.
2536 * The first element of the array is the number of pointers.
2539 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2541 MONO_REQ_GC_NEUTRAL_MODE;
2546 if (remote_class == NULL) {
2547 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2548 key = (void **)g_malloc (sizeof(gpointer) * 3);
2549 key [0] = GINT_TO_POINTER (2);
2550 key [1] = mono_defaults.marshalbyrefobject_class;
2551 key [2] = extra_class;
2553 key = (void **)g_malloc (sizeof(gpointer) * 2);
2554 key [0] = GINT_TO_POINTER (1);
2555 key [1] = extra_class;
2558 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2559 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2560 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2561 key [1] = remote_class->proxy_class;
2563 // Keep the list of interfaces sorted
2564 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2565 if (extra_class && remote_class->interfaces [i] > extra_class) {
2566 key [j++] = extra_class;
2569 key [j] = remote_class->interfaces [i];
2572 key [j] = extra_class;
2574 // Replace the old class. The interface list is the same
2575 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2576 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2577 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2578 for (i = 0; i < remote_class->interface_count; i++)
2579 key [2 + i] = remote_class->interfaces [i];
2587 * copy_remote_class_key:
2589 * Make a copy of KEY in the domain and return the copy.
2592 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2594 MONO_REQ_GC_NEUTRAL_MODE
2596 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2597 gpointer *mp_key = (gpointer *)mono_domain_alloc (domain, key_size);
2599 memcpy (mp_key, key, key_size);
2605 * mono_remote_class:
2606 * @domain: the application domain
2607 * @class_name: name of the remote class
2609 * Creates and initializes a MonoRemoteClass object for a remote type.
2611 * Can raise an exception on failure.
2614 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2616 MONO_REQ_GC_UNSAFE_MODE;
2619 MonoRemoteClass *rc;
2620 gpointer* key, *mp_key;
2623 key = create_remote_class_key (NULL, proxy_class);
2625 mono_domain_lock (domain);
2626 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2630 mono_domain_unlock (domain);
2634 name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
2635 if (!mono_error_ok (&error)) {
2637 mono_domain_unlock (domain);
2638 mono_error_raise_exception (&error);
2641 mp_key = copy_remote_class_key (domain, key);
2645 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2646 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2647 rc->interface_count = 1;
2648 rc->interfaces [0] = proxy_class;
2649 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2651 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2652 rc->interface_count = 0;
2653 rc->proxy_class = proxy_class;
2656 rc->default_vtable = NULL;
2657 rc->xdomain_vtable = NULL;
2658 rc->proxy_class_name = name;
2659 #ifndef DISABLE_PERFCOUNTERS
2660 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2663 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2665 mono_domain_unlock (domain);
2670 * clone_remote_class:
2671 * Creates a copy of the remote_class, adding the provided class or interface
2673 static MonoRemoteClass*
2674 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2676 MONO_REQ_GC_NEUTRAL_MODE;
2678 MonoRemoteClass *rc;
2679 gpointer* key, *mp_key;
2681 key = create_remote_class_key (remote_class, extra_class);
2682 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2688 mp_key = copy_remote_class_key (domain, key);
2692 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2694 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2695 rc->proxy_class = remote_class->proxy_class;
2696 rc->interface_count = remote_class->interface_count + 1;
2698 // Keep the list of interfaces sorted, since the hash key of
2699 // the remote class depends on this
2700 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2701 if (remote_class->interfaces [i] > extra_class && i == j)
2702 rc->interfaces [j++] = extra_class;
2703 rc->interfaces [j] = remote_class->interfaces [i];
2706 rc->interfaces [j] = extra_class;
2708 // Replace the old class. The interface array is the same
2709 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2710 rc->proxy_class = extra_class;
2711 rc->interface_count = remote_class->interface_count;
2712 if (rc->interface_count > 0)
2713 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2716 rc->default_vtable = NULL;
2717 rc->xdomain_vtable = NULL;
2718 rc->proxy_class_name = remote_class->proxy_class_name;
2720 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2726 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2728 MONO_REQ_GC_UNSAFE_MODE;
2730 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2731 mono_domain_lock (domain);
2732 if (rp->target_domain_id != -1) {
2733 if (remote_class->xdomain_vtable == NULL)
2734 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2735 mono_domain_unlock (domain);
2736 mono_loader_unlock ();
2737 return remote_class->xdomain_vtable;
2739 if (remote_class->default_vtable == NULL) {
2742 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2743 klass = mono_class_from_mono_type (type);
2745 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)))
2746 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2749 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2752 mono_domain_unlock (domain);
2753 mono_loader_unlock ();
2754 return remote_class->default_vtable;
2758 * mono_upgrade_remote_class:
2759 * @domain: the application domain
2760 * @tproxy: the proxy whose remote class has to be upgraded.
2761 * @klass: class to which the remote class can be casted.
2763 * Updates the vtable of the remote class by adding the necessary method slots
2764 * and interface offsets so it can be safely casted to klass. klass can be a
2765 * class or an interface.
2768 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2770 MONO_REQ_GC_UNSAFE_MODE;
2772 MonoTransparentProxy *tproxy;
2773 MonoRemoteClass *remote_class;
2774 gboolean redo_vtable;
2776 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2777 mono_domain_lock (domain);
2779 tproxy = (MonoTransparentProxy*) proxy_object;
2780 remote_class = tproxy->remote_class;
2782 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2785 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2786 if (remote_class->interfaces [i] == klass)
2787 redo_vtable = FALSE;
2790 redo_vtable = (remote_class->proxy_class != klass);
2794 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2795 proxy_object->vtable = (MonoVTable *)mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2798 mono_domain_unlock (domain);
2799 mono_loader_unlock ();
2801 #endif /* DISABLE_REMOTING */
2805 * mono_object_get_virtual_method:
2806 * @obj: object to operate on.
2809 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2810 * the instance of a callvirt of method.
2813 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2815 MONO_REQ_GC_UNSAFE_MODE;
2818 MonoMethod **vtable;
2819 gboolean is_proxy = FALSE;
2820 MonoMethod *res = NULL;
2822 klass = mono_object_class (obj);
2823 #ifndef DISABLE_REMOTING
2824 if (klass == mono_defaults.transparent_proxy_class) {
2825 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2830 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2833 mono_class_setup_vtable (klass);
2834 vtable = klass->vtable;
2836 if (method->slot == -1) {
2837 /* method->slot might not be set for instances of generic methods */
2838 if (method->is_inflated) {
2839 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2840 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2843 g_assert_not_reached ();
2847 /* check method->slot is a valid index: perform isinstance? */
2848 if (method->slot != -1) {
2849 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2851 gboolean variance_used = FALSE;
2852 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2853 g_assert (iface_offset > 0);
2854 res = vtable [iface_offset + method->slot];
2857 res = vtable [method->slot];
2861 #ifndef DISABLE_REMOTING
2863 /* It may be an interface, abstract class method or generic method */
2864 if (!res || mono_method_signature (res)->generic_param_count)
2867 /* generic methods demand invoke_with_check */
2868 if (mono_method_signature (res)->generic_param_count)
2869 res = mono_marshal_get_remoting_invoke_with_check (res);
2872 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2873 res = mono_cominterop_get_invoke (res);
2876 res = mono_marshal_get_remoting_invoke (res);
2881 if (method->is_inflated) {
2883 /* Have to inflate the result */
2884 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, &error);
2885 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
2895 do_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2897 MONO_REQ_GC_UNSAFE_MODE;
2899 MonoObject *result = NULL;
2901 g_assert (callbacks.runtime_invoke);
2903 mono_error_init (error);
2905 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2906 mono_profiler_method_start_invoke (method);
2908 MONO_PREPARE_RESET_BLOCKING;
2910 result = callbacks.runtime_invoke (method, obj, params, exc, error);
2912 MONO_FINISH_RESET_BLOCKING;
2914 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2915 mono_profiler_method_end_invoke (method);
2917 if (!mono_error_ok (error))
2924 * mono_runtime_invoke:
2925 * @method: method to invoke
2926 * @obJ: object instance
2927 * @params: arguments to the method
2928 * @exc: exception information.
2930 * Invokes the method represented by @method on the object @obj.
2932 * obj is the 'this' pointer, it should be NULL for static
2933 * methods, a MonoObject* for object instances and a pointer to
2934 * the value type for value types.
2936 * The params array contains the arguments to the method with the
2937 * same convention: MonoObject* pointers for object instances and
2938 * pointers to the value type otherwise.
2940 * From unmanaged code you'll usually use the
2941 * mono_runtime_invoke() variant.
2943 * Note that this function doesn't handle virtual methods for
2944 * you, it will exec the exact method you pass: we still need to
2945 * expose a function to lookup the derived class implementation
2946 * of a virtual method (there are examples of this in the code,
2949 * You can pass NULL as the exc argument if you don't want to
2950 * catch exceptions, otherwise, *exc will be set to the exception
2951 * thrown, if any. if an exception is thrown, you can't use the
2952 * MonoObject* result from the function.
2954 * If the method returns a value type, it is boxed in an object
2958 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2963 res = mono_runtime_try_invoke (method, obj, params, exc, &error);
2964 if (*exc == NULL && !mono_error_ok(&error)) {
2965 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
2967 mono_error_cleanup (&error);
2969 res = mono_runtime_invoke_checked (method, obj, params, &error);
2970 mono_error_raise_exception (&error);
2976 * mono_runtime_try_invoke:
2977 * @method: method to invoke
2978 * @obJ: object instance
2979 * @params: arguments to the method
2980 * @exc: exception information.
2981 * @error: set on error
2983 * Invokes the method represented by @method on the object @obj.
2985 * obj is the 'this' pointer, it should be NULL for static
2986 * methods, a MonoObject* for object instances and a pointer to
2987 * the value type for value types.
2989 * The params array contains the arguments to the method with the
2990 * same convention: MonoObject* pointers for object instances and
2991 * pointers to the value type otherwise.
2993 * From unmanaged code you'll usually use the
2994 * mono_runtime_invoke() variant.
2996 * Note that this function doesn't handle virtual methods for
2997 * you, it will exec the exact method you pass: we still need to
2998 * expose a function to lookup the derived class implementation
2999 * of a virtual method (there are examples of this in the code,
3002 * For this function, you must not pass NULL as the exc argument if
3003 * you don't want to catch exceptions, use
3004 * mono_runtime_invoke_checked(). If an exception is thrown, you
3005 * can't use the MonoObject* result from the function.
3007 * If this method cannot be invoked, @error will be set and @exc and
3008 * the return value must not be used.
3010 * If the method returns a value type, it is boxed in an object
3014 mono_runtime_try_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError* error)
3016 MONO_REQ_GC_UNSAFE_MODE;
3018 g_assert (exc != NULL);
3020 if (mono_runtime_get_no_exec ())
3021 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
3023 return do_runtime_invoke (method, obj, params, exc, error);
3027 * mono_runtime_invoke_checked:
3028 * @method: method to invoke
3029 * @obJ: object instance
3030 * @params: arguments to the method
3031 * @error: set on error
3033 * Invokes the method represented by @method on the object @obj.
3035 * obj is the 'this' pointer, it should be NULL for static
3036 * methods, a MonoObject* for object instances and a pointer to
3037 * the value type for value types.
3039 * The params array contains the arguments to the method with the
3040 * same convention: MonoObject* pointers for object instances and
3041 * pointers to the value type otherwise.
3043 * From unmanaged code you'll usually use the
3044 * mono_runtime_invoke() variant.
3046 * Note that this function doesn't handle virtual methods for
3047 * you, it will exec the exact method you pass: we still need to
3048 * expose a function to lookup the derived class implementation
3049 * of a virtual method (there are examples of this in the code,
3052 * If an exception is thrown, you can't use the MonoObject* result
3053 * from the function.
3055 * If this method cannot be invoked, @error will be set. If the
3056 * method throws an exception (and we're in coop mode) the exception
3057 * will be set in @error.
3059 * If the method returns a value type, it is boxed in an object
3063 mono_runtime_invoke_checked (MonoMethod *method, void *obj, void **params, MonoError* error)
3065 MONO_REQ_GC_UNSAFE_MODE;
3067 if (mono_runtime_get_no_exec ())
3068 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
3070 return do_runtime_invoke (method, obj, params, NULL, error);
3074 * mono_method_get_unmanaged_thunk:
3075 * @method: method to generate a thunk for.
3077 * Returns an unmanaged->managed thunk that can be used to call
3078 * a managed method directly from C.
3080 * The thunk's C signature closely matches the managed signature:
3082 * C#: public bool Equals (object obj);
3083 * C: typedef MonoBoolean (*Equals)(MonoObject*,
3084 * MonoObject*, MonoException**);
3086 * The 1st ("this") parameter must not be used with static methods:
3088 * C#: public static bool ReferenceEquals (object a, object b);
3089 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
3092 * The last argument must be a non-null pointer of a MonoException* pointer.
3093 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
3094 * exception has been thrown in managed code. Otherwise it will point
3095 * to the MonoException* caught by the thunk. In this case, the result of
3096 * the thunk is undefined:
3098 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
3099 * MonoException *ex = NULL;
3100 * Equals func = mono_method_get_unmanaged_thunk (method);
3101 * MonoBoolean res = func (thisObj, objToCompare, &ex);
3103 * // handle exception
3106 * The calling convention of the thunk matches the platform's default
3107 * convention. This means that under Windows, C declarations must
3108 * contain the __stdcall attribute:
3110 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
3111 * MonoObject*, MonoException**);
3115 * Value type arguments and return values are treated as they were objects:
3117 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
3118 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
3120 * Arguments must be properly boxed upon trunk's invocation, while return
3121 * values must be unboxed.
3124 mono_method_get_unmanaged_thunk (MonoMethod *method)
3126 MONO_REQ_GC_NEUTRAL_MODE;
3127 MONO_REQ_API_ENTRYPOINT;
3131 MONO_PREPARE_RESET_BLOCKING;
3132 method = mono_marshal_get_thunk_invoke_wrapper (method);
3133 res = mono_compile_method (method);
3134 MONO_FINISH_RESET_BLOCKING;
3140 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
3142 MONO_REQ_GC_UNSAFE_MODE;
3146 /* object fields cannot be byref, so we don't need a
3148 gpointer *p = (gpointer*)dest;
3155 case MONO_TYPE_BOOLEAN:
3157 case MONO_TYPE_U1: {
3158 guint8 *p = (guint8*)dest;
3159 *p = value ? *(guint8*)value : 0;
3164 case MONO_TYPE_CHAR: {
3165 guint16 *p = (guint16*)dest;
3166 *p = value ? *(guint16*)value : 0;
3169 #if SIZEOF_VOID_P == 4
3174 case MONO_TYPE_U4: {
3175 gint32 *p = (gint32*)dest;
3176 *p = value ? *(gint32*)value : 0;
3179 #if SIZEOF_VOID_P == 8
3184 case MONO_TYPE_U8: {
3185 gint64 *p = (gint64*)dest;
3186 *p = value ? *(gint64*)value : 0;
3189 case MONO_TYPE_R4: {
3190 float *p = (float*)dest;
3191 *p = value ? *(float*)value : 0;
3194 case MONO_TYPE_R8: {
3195 double *p = (double*)dest;
3196 *p = value ? *(double*)value : 0;
3199 case MONO_TYPE_STRING:
3200 case MONO_TYPE_SZARRAY:
3201 case MONO_TYPE_CLASS:
3202 case MONO_TYPE_OBJECT:
3203 case MONO_TYPE_ARRAY:
3204 mono_gc_wbarrier_generic_store (dest, deref_pointer ? *(MonoObject **)value : (MonoObject *)value);
3206 case MONO_TYPE_FNPTR:
3207 case MONO_TYPE_PTR: {
3208 gpointer *p = (gpointer*)dest;
3209 *p = deref_pointer? *(gpointer*)value: value;
3212 case MONO_TYPE_VALUETYPE:
3213 /* note that 't' and 'type->type' can be different */
3214 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3215 t = mono_class_enum_basetype (type->data.klass)->type;
3218 MonoClass *klass = mono_class_from_mono_type (type);
3219 int size = mono_class_value_size (klass, NULL);
3221 mono_gc_bzero_atomic (dest, size);
3223 mono_gc_wbarrier_value_copy (dest, value, 1, klass);
3226 case MONO_TYPE_GENERICINST:
3227 t = type->data.generic_class->container_class->byval_arg.type;
3230 g_error ("got type %x", type->type);
3235 * mono_field_set_value:
3236 * @obj: Instance object
3237 * @field: MonoClassField describing the field to set
3238 * @value: The value to be set
3240 * Sets the value of the field described by @field in the object instance @obj
3241 * to the value passed in @value. This method should only be used for instance
3242 * fields. For static fields, use mono_field_static_set_value.
3244 * The value must be on the native format of the field type.
3247 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3249 MONO_REQ_GC_UNSAFE_MODE;
3253 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3255 dest = (char*)obj + field->offset;
3256 mono_copy_value (field->type, dest, value, FALSE);
3260 * mono_field_static_set_value:
3261 * @field: MonoClassField describing the field to set
3262 * @value: The value to be set
3264 * Sets the value of the static field described by @field
3265 * to the value passed in @value.
3267 * The value must be on the native format of the field type.
3270 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3272 MONO_REQ_GC_UNSAFE_MODE;
3276 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3277 /* you cant set a constant! */
3278 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3280 if (field->offset == -1) {
3281 /* Special static */
3284 mono_domain_lock (vt->domain);
3285 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3286 mono_domain_unlock (vt->domain);
3287 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3289 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3291 mono_copy_value (field->type, dest, value, FALSE);
3295 * mono_vtable_get_static_field_data:
3297 * Internal use function: return a pointer to the memory holding the static fields
3298 * for a class or NULL if there are no static fields.
3299 * This is exported only for use by the debugger.
3302 mono_vtable_get_static_field_data (MonoVTable *vt)
3304 MONO_REQ_GC_NEUTRAL_MODE
3306 if (!vt->has_static_fields)
3308 return vt->vtable [vt->klass->vtable_size];
3312 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3314 MONO_REQ_GC_UNSAFE_MODE;
3318 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3319 if (field->offset == -1) {
3320 /* Special static */
3323 mono_domain_lock (vt->domain);
3324 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3325 mono_domain_unlock (vt->domain);
3326 src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3328 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3331 src = (guint8*)obj + field->offset;
3338 * mono_field_get_value:
3339 * @obj: Object instance
3340 * @field: MonoClassField describing the field to fetch information from
3341 * @value: pointer to the location where the value will be stored
3343 * Use this routine to get the value of the field @field in the object
3346 * The pointer provided by value must be of the field type, for reference
3347 * types this is a MonoObject*, for value types its the actual pointer to
3352 * mono_field_get_value (obj, int_field, &i);
3355 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3357 MONO_REQ_GC_UNSAFE_MODE;
3363 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3365 src = (char*)obj + field->offset;
3366 mono_copy_value (field->type, value, src, TRUE);
3370 * mono_field_get_value_object:
3371 * @domain: domain where the object will be created (if boxing)
3372 * @field: MonoClassField describing the field to fetch information from
3373 * @obj: The object instance for the field.
3375 * Returns: a new MonoObject with the value from the given field. If the
3376 * field represents a value type, the value is boxed.
3380 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3383 MonoObject* result = mono_field_get_value_object_checked (domain, field, obj, &error);
3384 mono_error_assert_ok (&error);
3389 * mono_field_get_value_object_checked:
3390 * @domain: domain where the object will be created (if boxing)
3391 * @field: MonoClassField describing the field to fetch information from
3392 * @obj: The object instance for the field.
3393 * @error: Set on error.
3395 * Returns: a new MonoObject with the value from the given field. If the
3396 * field represents a value type, the value is boxed. On error returns NULL and sets @error.
3400 mono_field_get_value_object_checked (MonoDomain *domain, MonoClassField *field, MonoObject *obj, MonoError *error)
3402 MONO_REQ_GC_UNSAFE_MODE;
3404 mono_error_init (error);
3408 MonoVTable *vtable = NULL;
3410 gboolean is_static = FALSE;
3411 gboolean is_ref = FALSE;
3412 gboolean is_literal = FALSE;
3413 gboolean is_ptr = FALSE;
3414 MonoType *type = mono_field_get_type_checked (field, error);
3416 return_val_if_nok (error, NULL);
3418 switch (type->type) {
3419 case MONO_TYPE_STRING:
3420 case MONO_TYPE_OBJECT:
3421 case MONO_TYPE_CLASS:
3422 case MONO_TYPE_ARRAY:
3423 case MONO_TYPE_SZARRAY:
3428 case MONO_TYPE_BOOLEAN:
3431 case MONO_TYPE_CHAR:
3440 case MONO_TYPE_VALUETYPE:
3441 is_ref = type->byref;
3443 case MONO_TYPE_GENERICINST:
3444 is_ref = !mono_type_generic_inst_is_valuetype (type);
3450 g_error ("type 0x%x not handled in "
3451 "mono_field_get_value_object", type->type);
3455 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3458 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3462 vtable = mono_class_vtable_full (domain, field->parent, error);
3463 return_val_if_nok (error, NULL);
3465 if (!vtable->initialized) {
3466 mono_runtime_class_init_full (vtable, error);
3467 return_val_if_nok (error, NULL);
3476 get_default_field_value (domain, field, &o);
3477 } else if (is_static) {
3478 mono_field_static_get_value (vtable, field, &o);
3480 mono_field_get_value (obj, field, &o);
3486 static MonoMethod *m;
3492 MonoClass *ptr_klass = mono_class_get_pointer_class ();
3493 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3499 get_default_field_value (domain, field, v);
3500 } else if (is_static) {
3501 mono_field_static_get_value (vtable, field, v);
3503 mono_field_get_value (obj, field, v);
3506 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3507 args [0] = ptr ? *ptr : NULL;
3508 args [1] = mono_type_get_object_checked (mono_domain_get (), type, error);
3509 return_val_if_nok (error, NULL);
3511 o = mono_runtime_invoke_checked (m, NULL, args, error);
3512 return_val_if_nok (error, NULL);
3517 /* boxed value type */
3518 klass = mono_class_from_mono_type (type);
3520 if (mono_class_is_nullable (klass))
3521 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
3523 o = mono_object_new_checked (domain, klass, error);
3524 return_val_if_nok (error, NULL);
3525 v = ((gchar *) o) + sizeof (MonoObject);
3528 get_default_field_value (domain, field, v);
3529 } else if (is_static) {
3530 mono_field_static_get_value (vtable, field, v);
3532 mono_field_get_value (obj, field, v);
3539 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
3541 MONO_REQ_GC_UNSAFE_MODE;
3544 const char *p = blob;
3545 mono_metadata_decode_blob_size (p, &p);
3548 case MONO_TYPE_BOOLEAN:
3551 *(guint8 *) value = *p;
3553 case MONO_TYPE_CHAR:
3556 *(guint16*) value = read16 (p);
3560 *(guint32*) value = read32 (p);
3564 *(guint64*) value = read64 (p);
3567 readr4 (p, (float*) value);
3570 readr8 (p, (double*) value);
3572 case MONO_TYPE_STRING:
3573 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3575 case MONO_TYPE_CLASS:
3576 *(gpointer*) value = NULL;
3580 g_warning ("type 0x%02x should not be in constant table", type);
3586 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3588 MONO_REQ_GC_NEUTRAL_MODE;
3590 MonoTypeEnum def_type;
3593 data = mono_class_get_field_default_value (field, &def_type);
3594 mono_get_constant_value_from_blob (domain, def_type, data, value);
3598 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value)
3600 MONO_REQ_GC_UNSAFE_MODE;
3604 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3606 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3607 get_default_field_value (vt->domain, field, value);
3611 if (field->offset == -1) {
3612 /* Special static */
3613 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3614 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3616 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3618 mono_copy_value (field->type, value, src, TRUE);
3622 * mono_field_static_get_value:
3623 * @vt: vtable to the object
3624 * @field: MonoClassField describing the field to fetch information from
3625 * @value: where the value is returned
3627 * Use this routine to get the value of the static field @field value.
3629 * The pointer provided by value must be of the field type, for reference
3630 * types this is a MonoObject*, for value types its the actual pointer to
3635 * mono_field_static_get_value (vt, int_field, &i);
3638 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3640 MONO_REQ_GC_NEUTRAL_MODE;
3642 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value);
3646 * mono_property_set_value:
3647 * @prop: MonoProperty to set
3648 * @obj: instance object on which to act
3649 * @params: parameters to pass to the propery
3650 * @exc: optional exception
3652 * Invokes the property's set method with the given arguments on the
3653 * object instance obj (or NULL for static properties).
3655 * You can pass NULL as the exc argument if you don't want to
3656 * catch exceptions, otherwise, *exc will be set to the exception
3657 * thrown, if any. if an exception is thrown, you can't use the
3658 * MonoObject* result from the function.
3661 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3663 MONO_REQ_GC_UNSAFE_MODE;
3666 do_runtime_invoke (prop->set, obj, params, exc, &error);
3667 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3668 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3670 mono_error_raise_exception (&error); /* FIXME don't raise here */
3675 * mono_property_get_value:
3676 * @prop: MonoProperty to fetch
3677 * @obj: instance object on which to act
3678 * @params: parameters to pass to the propery
3679 * @exc: optional exception
3681 * Invokes the property's get method with the given arguments on the
3682 * object instance obj (or NULL for static properties).
3684 * You can pass NULL as the exc argument if you don't want to
3685 * catch exceptions, otherwise, *exc will be set to the exception
3686 * thrown, if any. if an exception is thrown, you can't use the
3687 * MonoObject* result from the function.
3689 * Returns: the value from invoking the get method on the property.
3692 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3694 MONO_REQ_GC_UNSAFE_MODE;
3697 MonoObject *val = do_runtime_invoke (prop->get, obj, params, exc, &error);
3698 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3699 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3701 mono_error_raise_exception (&error); /* FIXME don't raise here */
3708 * mono_nullable_init:
3709 * @buf: The nullable structure to initialize.
3710 * @value: the value to initialize from
3711 * @klass: the type for the object
3713 * Initialize the nullable structure pointed to by @buf from @value which
3714 * should be a boxed value type. The size of @buf should be able to hold
3715 * as much data as the @klass->instance_size (which is the number of bytes
3716 * that will be copies).
3718 * Since Nullables have variable structure, we can not define a C
3719 * structure for them.
3722 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3724 MONO_REQ_GC_UNSAFE_MODE;
3726 MonoClass *param_class = klass->cast_class;
3728 mono_class_setup_fields_locking (klass);
3729 g_assert (klass->fields_inited);
3731 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3732 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3734 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3736 if (param_class->has_references)
3737 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3739 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3741 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3746 * mono_nullable_box:
3747 * @buf: The buffer representing the data to be boxed
3748 * @klass: the type to box it as.
3750 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3754 mono_nullable_box (guint8 *buf, MonoClass *klass)
3756 MONO_REQ_GC_UNSAFE_MODE;
3760 MonoClass *param_class = klass->cast_class;
3762 mono_class_setup_fields_locking (klass);
3763 g_assert (klass->fields_inited);
3765 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3766 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3768 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3769 MonoObject *o = mono_object_new_checked (mono_domain_get (), param_class, &error);
3770 mono_error_raise_exception (&error); /* FIXME don't raise here */
3771 if (param_class->has_references)
3772 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3774 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3782 * mono_get_delegate_invoke:
3783 * @klass: The delegate class
3785 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3788 mono_get_delegate_invoke (MonoClass *klass)
3790 MONO_REQ_GC_NEUTRAL_MODE;
3794 /* This is called at runtime, so avoid the slower search in metadata */
3795 mono_class_setup_methods (klass);
3796 if (mono_class_has_failure (klass))
3798 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3803 * mono_get_delegate_begin_invoke:
3804 * @klass: The delegate class
3806 * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3809 mono_get_delegate_begin_invoke (MonoClass *klass)
3811 MONO_REQ_GC_NEUTRAL_MODE;
3815 /* This is called at runtime, so avoid the slower search in metadata */
3816 mono_class_setup_methods (klass);
3817 if (mono_class_has_failure (klass))
3819 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3824 * mono_get_delegate_end_invoke:
3825 * @klass: The delegate class
3827 * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3830 mono_get_delegate_end_invoke (MonoClass *klass)
3832 MONO_REQ_GC_NEUTRAL_MODE;
3836 /* This is called at runtime, so avoid the slower search in metadata */
3837 mono_class_setup_methods (klass);
3838 if (mono_class_has_failure (klass))
3840 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3845 * mono_runtime_delegate_invoke:
3846 * @delegate: pointer to a delegate object.
3847 * @params: parameters for the delegate.
3848 * @exc: Pointer to the exception result.
3850 * Invokes the delegate method @delegate with the parameters provided.
3852 * You can pass NULL as the exc argument if you don't want to
3853 * catch exceptions, otherwise, *exc will be set to the exception
3854 * thrown, if any. if an exception is thrown, you can't use the
3855 * MonoObject* result from the function.
3858 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3860 MONO_REQ_GC_UNSAFE_MODE;
3864 MonoClass *klass = delegate->vtable->klass;
3867 im = mono_get_delegate_invoke (klass);
3869 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3872 o = mono_runtime_try_invoke (im, delegate, params, exc, &error);
3873 if (*exc == NULL && !mono_error_ok (&error))
3874 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3876 mono_error_cleanup (&error);
3878 o = mono_runtime_invoke_checked (im, delegate, params, &error);
3879 mono_error_raise_exception (&error); /* FIXME don't raise here */
3885 static char **main_args = NULL;
3886 static int num_main_args = 0;
3889 * mono_runtime_get_main_args:
3891 * Returns: a MonoArray with the arguments passed to the main program
3894 mono_runtime_get_main_args (void)
3896 MONO_REQ_GC_UNSAFE_MODE;
3900 MonoDomain *domain = mono_domain_get ();
3902 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3904 for (i = 0; i < num_main_args; ++i)
3905 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3911 free_main_args (void)
3913 MONO_REQ_GC_NEUTRAL_MODE;
3917 for (i = 0; i < num_main_args; ++i)
3918 g_free (main_args [i]);
3925 * mono_runtime_set_main_args:
3926 * @argc: number of arguments from the command line
3927 * @argv: array of strings from the command line
3929 * Set the command line arguments from an embedding application that doesn't otherwise call
3930 * mono_runtime_run_main ().
3933 mono_runtime_set_main_args (int argc, char* argv[])
3935 MONO_REQ_GC_NEUTRAL_MODE;
3940 main_args = g_new0 (char*, argc);
3941 num_main_args = argc;
3943 for (i = 0; i < argc; ++i) {
3946 utf8_arg = mono_utf8_from_external (argv[i]);
3947 if (utf8_arg == NULL) {
3948 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
3949 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3953 main_args [i] = utf8_arg;
3960 * mono_runtime_run_main:
3961 * @method: the method to start the application with (usually Main)
3962 * @argc: number of arguments from the command line
3963 * @argv: array of strings from the command line
3964 * @exc: excetption results
3966 * Execute a standard Main() method (argc/argv contains the
3967 * executable name). This method also sets the command line argument value
3968 * needed by System.Environment.
3973 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3976 MONO_REQ_GC_UNSAFE_MODE;
3979 MonoArray *args = NULL;
3980 MonoDomain *domain = mono_domain_get ();
3981 gchar *utf8_fullpath;
3982 MonoMethodSignature *sig;
3984 g_assert (method != NULL);
3986 mono_thread_set_main (mono_thread_current ());
3988 main_args = g_new0 (char*, argc);
3989 num_main_args = argc;
3991 if (!g_path_is_absolute (argv [0])) {
3992 gchar *basename = g_path_get_basename (argv [0]);
3993 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3997 utf8_fullpath = mono_utf8_from_external (fullpath);
3998 if(utf8_fullpath == NULL) {
3999 /* Printing the arg text will cause glib to
4000 * whinge about "Invalid UTF-8", but at least
4001 * its relevant, and shows the problem text
4004 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
4005 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4012 utf8_fullpath = mono_utf8_from_external (argv[0]);
4013 if(utf8_fullpath == NULL) {
4014 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
4015 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4020 main_args [0] = utf8_fullpath;
4022 for (i = 1; i < argc; ++i) {
4025 utf8_arg=mono_utf8_from_external (argv[i]);
4026 if(utf8_arg==NULL) {
4027 /* Ditto the comment about Invalid UTF-8 here */
4028 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
4029 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4033 main_args [i] = utf8_arg;
4038 sig = mono_method_signature (method);
4040 g_print ("Unable to load Main method.\n");
4044 if (sig->param_count) {
4045 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
4046 for (i = 0; i < argc; ++i) {
4047 /* The encodings should all work, given that
4048 * we've checked all these args for the
4051 gchar *str = mono_utf8_from_external (argv [i]);
4052 MonoString *arg = mono_string_new (domain, str);
4053 mono_array_setref (args, i, arg);
4057 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
4060 mono_assembly_set_main (method->klass->image->assembly);
4062 return mono_runtime_exec_main (method, args, exc);
4066 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4068 static MonoMethod *serialize_method;
4074 if (!serialize_method) {
4075 MonoClass *klass = mono_class_get_remoting_services_class ();
4076 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
4079 if (!serialize_method) {
4084 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
4089 array = mono_runtime_try_invoke (serialize_method, NULL, params, exc, &error);
4090 if (*exc == NULL && !mono_error_ok (&error))
4091 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert serialize_object to MonoError */
4093 mono_error_cleanup (&error);
4102 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4104 MONO_REQ_GC_UNSAFE_MODE;
4106 static MonoMethod *deserialize_method;
4112 if (!deserialize_method) {
4113 MonoClass *klass = mono_class_get_remoting_services_class ();
4114 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
4116 if (!deserialize_method) {
4124 result = mono_runtime_try_invoke (deserialize_method, NULL, params, exc, &error);
4125 if (*exc == NULL && !mono_error_ok (&error))
4126 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert deserialize_object to MonoError */
4128 mono_error_cleanup (&error);
4136 #ifndef DISABLE_REMOTING
4138 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
4140 MONO_REQ_GC_UNSAFE_MODE;
4142 static MonoMethod *get_proxy_method;
4145 MonoDomain *domain = mono_domain_get ();
4146 MonoRealProxy *real_proxy;
4147 MonoReflectionType *reflection_type;
4148 MonoTransparentProxy *transparent_proxy;
4150 if (!get_proxy_method)
4151 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
4153 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
4155 real_proxy = (MonoRealProxy*) mono_object_new_checked (domain, mono_defaults.real_proxy_class, &error);
4156 mono_error_raise_exception (&error); /* FIXME don't raise here */
4157 reflection_type = mono_type_get_object_checked (domain, &obj->vtable->klass->byval_arg, &error);
4158 mono_error_raise_exception (&error); /* FIXME don't raise here */
4160 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
4161 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
4165 transparent_proxy = (MonoTransparentProxy*) mono_runtime_try_invoke (get_proxy_method, real_proxy, NULL, exc, &error);
4166 if (*exc == NULL && !mono_error_ok (&error))
4167 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME change make_transparent_proxy outarg to MonoError */
4169 mono_error_cleanup (&error);
4173 return (MonoObject*) transparent_proxy;
4175 #endif /* DISABLE_REMOTING */
4178 * mono_object_xdomain_representation
4180 * @target_domain: a domain
4181 * @exc: pointer to a MonoObject*
4183 * Creates a representation of obj in the domain target_domain. This
4184 * is either a copy of obj arrived through via serialization and
4185 * deserialization or a proxy, depending on whether the object is
4186 * serializable or marshal by ref. obj must not be in target_domain.
4188 * If the object cannot be represented in target_domain, NULL is
4189 * returned and *exc is set to an appropriate exception.
4192 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
4194 MONO_REQ_GC_UNSAFE_MODE;
4196 MonoObject *deserialized = NULL;
4197 gboolean failure = FALSE;
4199 g_assert (exc != NULL);
4202 #ifndef DISABLE_REMOTING
4203 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
4204 deserialized = make_transparent_proxy (obj, &failure, exc);
4209 MonoDomain *domain = mono_domain_get ();
4210 MonoObject *serialized;
4212 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
4213 serialized = serialize_object (obj, &failure, exc);
4214 mono_domain_set_internal_with_options (target_domain, FALSE);
4216 deserialized = deserialize_object (serialized, &failure, exc);
4217 if (domain != target_domain)
4218 mono_domain_set_internal_with_options (domain, FALSE);
4221 return deserialized;
4224 /* Used in call_unhandled_exception_delegate */
4226 create_unhandled_exception_eventargs (MonoObject *exc)
4228 MONO_REQ_GC_UNSAFE_MODE;
4233 MonoMethod *method = NULL;
4234 MonoBoolean is_terminating = TRUE;
4237 klass = mono_class_get_unhandled_exception_event_args_class ();
4238 mono_class_init (klass);
4240 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4241 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
4245 args [1] = &is_terminating;
4247 obj = mono_object_new_checked (mono_domain_get (), klass, &error);
4248 mono_error_raise_exception (&error); /* FIXME don't raise here */
4250 mono_runtime_invoke_checked (method, obj, args, &error);
4251 mono_error_raise_exception (&error); /* FIXME don't raise here */
4256 /* Used in mono_unhandled_exception */
4258 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4259 MONO_REQ_GC_UNSAFE_MODE;
4261 MonoObject *e = NULL;
4263 MonoDomain *current_domain = mono_domain_get ();
4265 if (domain != current_domain)
4266 mono_domain_set_internal_with_options (domain, FALSE);
4268 g_assert (domain == mono_object_domain (domain->domain));
4270 if (mono_object_domain (exc) != domain) {
4271 MonoObject *serialization_exc;
4273 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
4275 if (serialization_exc) {
4277 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
4280 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4281 "System.Runtime.Serialization", "SerializationException",
4282 "Could not serialize unhandled exception.");
4286 g_assert (mono_object_domain (exc) == domain);
4288 pa [0] = domain->domain;
4289 pa [1] = create_unhandled_exception_eventargs (exc);
4290 mono_runtime_delegate_invoke (delegate, pa, &e);
4292 if (domain != current_domain)
4293 mono_domain_set_internal_with_options (current_domain, FALSE);
4297 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4298 if (!mono_error_ok (&error)) {
4299 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4300 mono_error_cleanup (&error);
4302 g_warning ("exception inside UnhandledException handler: %s\n", msg);
4308 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4311 * mono_runtime_unhandled_exception_policy_set:
4312 * @policy: the new policy
4314 * This is a VM internal routine.
4316 * Sets the runtime policy for handling unhandled exceptions.
4319 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4320 runtime_unhandled_exception_policy = policy;
4324 * mono_runtime_unhandled_exception_policy_get:
4326 * This is a VM internal routine.
4328 * Gets the runtime policy for handling unhandled exceptions.
4330 MonoRuntimeUnhandledExceptionPolicy
4331 mono_runtime_unhandled_exception_policy_get (void) {
4332 return runtime_unhandled_exception_policy;
4336 * mono_unhandled_exception:
4337 * @exc: exception thrown
4339 * This is a VM internal routine.
4341 * We call this function when we detect an unhandled exception
4342 * in the default domain.
4344 * It invokes the * UnhandledException event in AppDomain or prints
4345 * a warning to the console
4348 mono_unhandled_exception (MonoObject *exc)
4350 MONO_REQ_GC_UNSAFE_MODE;
4353 MonoClassField *field;
4354 MonoDomain *current_domain, *root_domain;
4355 MonoObject *current_appdomain_delegate = NULL, *root_appdomain_delegate = NULL;
4357 if (mono_class_has_parent (exc->vtable->klass, mono_defaults.threadabortexception_class))
4360 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4363 current_domain = mono_domain_get ();
4364 root_domain = mono_get_root_domain ();
4366 root_appdomain_delegate = mono_field_get_value_object_checked (root_domain, field, (MonoObject*) root_domain->domain, &error);
4367 mono_error_raise_exception (&error); /* FIXME don't raise here */
4368 if (current_domain != root_domain) {
4369 current_appdomain_delegate = mono_field_get_value_object_checked (current_domain, field, (MonoObject*) current_domain->domain, &error);
4370 mono_error_raise_exception (&error); /* FIXME don't raise here */
4373 if (!current_appdomain_delegate && !root_appdomain_delegate) {
4374 mono_print_unhandled_exception (exc);
4376 if (root_appdomain_delegate)
4377 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4378 if (current_appdomain_delegate)
4379 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4382 /* set exitcode only if we will abort the process */
4383 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4384 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4386 mono_environment_exitcode_set (1);
4391 * mono_runtime_exec_managed_code:
4392 * @domain: Application domain
4393 * @main_func: function to invoke from the execution thread
4394 * @main_args: parameter to the main_func
4396 * Launch a new thread to execute a function
4398 * main_func is called back from the thread with main_args as the
4399 * parameter. The callback function is expected to start Main()
4400 * eventually. This function then waits for all managed threads to
4402 * It is not necesseray anymore to execute managed code in a subthread,
4403 * so this function should not be used anymore by default: just
4404 * execute the code and then call mono_thread_manage ().
4407 mono_runtime_exec_managed_code (MonoDomain *domain,
4408 MonoMainThreadFunc main_func,
4411 mono_thread_create (domain, main_func, main_args);
4413 mono_thread_manage ();
4417 * Execute a standard Main() method (args doesn't contain the
4421 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4423 MONO_REQ_GC_UNSAFE_MODE;
4429 MonoCustomAttrInfo* cinfo;
4430 gboolean has_stathread_attribute;
4431 MonoInternalThread* thread = mono_thread_internal_current ();
4437 domain = mono_object_domain (args);
4438 if (!domain->entry_assembly) {
4440 MonoAssembly *assembly;
4442 assembly = method->klass->image->assembly;
4443 domain->entry_assembly = assembly;
4444 /* Domains created from another domain already have application_base and configuration_file set */
4445 if (domain->setup->application_base == NULL) {
4446 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4449 if (domain->setup->configuration_file == NULL) {
4450 str = g_strconcat (assembly->image->name, ".config", NULL);
4451 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4453 mono_domain_set_options_from_config (domain);
4457 cinfo = mono_custom_attrs_from_method_checked (method, &error);
4458 mono_error_cleanup (&error); /* FIXME warn here? */
4460 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, mono_class_get_sta_thread_attribute_class ());
4462 mono_custom_attrs_free (cinfo);
4464 has_stathread_attribute = FALSE;
4466 if (has_stathread_attribute) {
4467 thread->apartment_state = ThreadApartmentState_STA;
4469 thread->apartment_state = ThreadApartmentState_MTA;
4471 mono_thread_init_apartment_state ();
4473 /* FIXME: check signature of method */
4474 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4477 res = mono_runtime_try_invoke (method, NULL, pa, exc, &error);
4478 if (*exc == NULL && !mono_error_ok (&error))
4479 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4481 mono_error_cleanup (&error);
4483 res = mono_runtime_invoke_checked (method, NULL, pa, &error);
4484 mono_error_raise_exception (&error); /* FIXME don't raise here */
4488 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4492 mono_environment_exitcode_set (rval);
4495 mono_runtime_try_invoke (method, NULL, pa, exc, &error);
4496 if (*exc == NULL && !mono_error_ok (&error))
4497 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4499 mono_error_cleanup (&error);
4501 mono_runtime_invoke_checked (method, NULL, pa, &error);
4502 mono_error_raise_exception (&error); /* FIXME don't raise here */
4508 /* If the return type of Main is void, only
4509 * set the exitcode if an exception was thrown
4510 * (we don't want to blow away an
4511 * explicitly-set exit code)
4514 mono_environment_exitcode_set (rval);
4522 * mono_runtime_invoke_array:
4523 * @method: method to invoke
4524 * @obJ: object instance
4525 * @params: arguments to the method
4526 * @exc: exception information.
4528 * Invokes the method represented by @method on the object @obj.
4530 * obj is the 'this' pointer, it should be NULL for static
4531 * methods, a MonoObject* for object instances and a pointer to
4532 * the value type for value types.
4534 * The params array contains the arguments to the method with the
4535 * same convention: MonoObject* pointers for object instances and
4536 * pointers to the value type otherwise. The _invoke_array
4537 * variant takes a C# object[] as the params argument (MonoArray
4538 * *params): in this case the value types are boxed inside the
4539 * respective reference representation.
4541 * From unmanaged code you'll usually use the
4542 * mono_runtime_invoke_checked() variant.
4544 * Note that this function doesn't handle virtual methods for
4545 * you, it will exec the exact method you pass: we still need to
4546 * expose a function to lookup the derived class implementation
4547 * of a virtual method (there are examples of this in the code,
4550 * You can pass NULL as the exc argument if you don't want to
4551 * catch exceptions, otherwise, *exc will be set to the exception
4552 * thrown, if any. if an exception is thrown, you can't use the
4553 * MonoObject* result from the function.
4555 * If the method returns a value type, it is boxed in an object
4559 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4562 MONO_REQ_GC_UNSAFE_MODE;
4565 MonoMethodSignature *sig = mono_method_signature (method);
4566 gpointer *pa = NULL;
4569 gboolean has_byref_nullables = FALSE;
4571 if (NULL != params) {
4572 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
4573 for (i = 0; i < mono_array_length (params); i++) {
4574 MonoType *t = sig->params [i];
4580 case MONO_TYPE_BOOLEAN:
4583 case MONO_TYPE_CHAR:
4592 case MONO_TYPE_VALUETYPE:
4593 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
4594 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4595 pa [i] = mono_array_get (params, MonoObject*, i);
4597 has_byref_nullables = TRUE;
4599 /* MS seems to create the objects if a null is passed in */
4600 if (!mono_array_get (params, MonoObject*, i)) {
4601 MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (sig->params [i]), &error);
4602 mono_error_raise_exception (&error); /* FIXME don't raise here */
4603 mono_array_setref (params, i, o);
4608 * We can't pass the unboxed vtype byref to the callee, since
4609 * that would mean the callee would be able to modify boxed
4610 * primitive types. So we (and MS) make a copy of the boxed
4611 * object, pass that to the callee, and replace the original
4612 * boxed object in the arg array with the copy.
4614 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4615 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
4616 mono_array_setref (params, i, copy);
4619 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4622 case MONO_TYPE_STRING:
4623 case MONO_TYPE_OBJECT:
4624 case MONO_TYPE_CLASS:
4625 case MONO_TYPE_ARRAY:
4626 case MONO_TYPE_SZARRAY:
4628 pa [i] = mono_array_addr (params, MonoObject*, i);
4629 // FIXME: I need to check this code path
4631 pa [i] = mono_array_get (params, MonoObject*, i);
4633 case MONO_TYPE_GENERICINST:
4635 t = &t->data.generic_class->container_class->this_arg;
4637 t = &t->data.generic_class->container_class->byval_arg;
4639 case MONO_TYPE_PTR: {
4642 /* The argument should be an IntPtr */
4643 arg = mono_array_get (params, MonoObject*, i);
4647 g_assert (arg->vtable->klass == mono_defaults.int_class);
4648 pa [i] = ((MonoIntPtr*)arg)->m_value;
4653 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
4658 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4661 if (mono_class_is_nullable (method->klass)) {
4662 /* Need to create a boxed vtype instead */
4668 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
4672 obj = mono_object_new_checked (mono_domain_get (), method->klass, &error);
4673 g_assert (obj && mono_error_ok (&error)); /*maybe we should raise a TLE instead?*/ /* FIXME don't swallow error */
4674 #ifndef DISABLE_REMOTING
4675 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
4676 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
4679 if (method->klass->valuetype)
4680 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
4683 } else if (method->klass->valuetype) {
4684 obj = mono_value_box (mono_domain_get (), method->klass, obj);
4688 mono_runtime_try_invoke (method, o, pa, exc, &error);
4689 if (*exc == NULL && !mono_error_ok (&error))
4690 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4692 mono_error_cleanup (&error);
4694 mono_runtime_invoke_checked (method, o, pa, &error);
4695 mono_error_raise_exception (&error); /* FIXME don't raise here */
4698 return (MonoObject *)obj;
4700 if (mono_class_is_nullable (method->klass)) {
4701 MonoObject *nullable;
4703 /* Convert the unboxed vtype into a Nullable structure */
4704 nullable = mono_object_new_checked (mono_domain_get (), method->klass, &error);
4705 mono_error_raise_exception (&error); /* FIXME don't raise here */
4707 mono_nullable_init ((guint8 *)mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
4708 obj = mono_object_unbox (nullable);
4711 /* obj must be already unboxed if needed */
4713 res = mono_runtime_try_invoke (method, obj, pa, exc, &error);
4714 if (*exc == NULL && !mono_error_ok (&error))
4715 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4717 mono_error_cleanup (&error);
4719 res = mono_runtime_invoke_checked (method, obj, pa, &error);
4720 mono_error_raise_exception (&error); /* FIXME don't raise here */
4723 if (sig->ret->type == MONO_TYPE_PTR) {
4724 MonoClass *pointer_class;
4725 static MonoMethod *box_method;
4727 MonoObject *box_exc;
4730 * The runtime-invoke wrapper returns a boxed IntPtr, need to
4731 * convert it to a Pointer object.
4733 pointer_class = mono_class_get_pointer_class ();
4735 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4737 g_assert (res->vtable->klass == mono_defaults.int_class);
4738 box_args [0] = ((MonoIntPtr*)res)->m_value;
4739 box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, &error);
4740 mono_error_raise_exception (&error); /* FIXME don't raise here */
4742 res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, &error);
4743 g_assert (box_exc == NULL);
4744 mono_error_assert_ok (&error);
4747 if (has_byref_nullables) {
4749 * The runtime invoke wrapper already converted byref nullables back,
4750 * and stored them in pa, we just need to copy them back to the
4753 for (i = 0; i < mono_array_length (params); i++) {
4754 MonoType *t = sig->params [i];
4756 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4757 mono_array_setref (params, i, pa [i]);
4767 * @klass: the class of the object that we want to create
4769 * Returns: a newly created object whose definition is
4770 * looked up using @klass. This will not invoke any constructors,
4771 * so the consumer of this routine has to invoke any constructors on
4772 * its own to initialize the object.
4774 * It returns NULL on failure.
4777 mono_object_new (MonoDomain *domain, MonoClass *klass)
4779 MONO_REQ_GC_UNSAFE_MODE;
4783 MonoObject * result = mono_object_new_checked (domain, klass, &error);
4785 mono_error_raise_exception (&error);
4790 ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
4792 MONO_REQ_GC_UNSAFE_MODE;
4796 MonoObject * result = mono_object_new_checked (domain, klass, &error);
4798 mono_error_raise_exception (&error);
4803 * mono_object_new_checked:
4804 * @klass: the class of the object that we want to create
4805 * @error: set on error
4807 * Returns: a newly created object whose definition is
4808 * looked up using @klass. This will not invoke any constructors,
4809 * so the consumer of this routine has to invoke any constructors on
4810 * its own to initialize the object.
4812 * It returns NULL on failure and sets @error.
4815 mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
4817 MONO_REQ_GC_UNSAFE_MODE;
4821 vtable = mono_class_vtable (domain, klass);
4822 g_assert (vtable); /* FIXME don't swallow the error */
4824 MonoObject *o = mono_object_new_specific_checked (vtable, error);
4829 * mono_object_new_pinned:
4831 * Same as mono_object_new, but the returned object will be pinned.
4832 * For SGEN, these objects will only be freed at appdomain unload.
4835 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
4837 MONO_REQ_GC_UNSAFE_MODE;
4841 mono_error_init (error);
4843 vtable = mono_class_vtable (domain, klass);
4844 g_assert (vtable); /* FIXME don't swallow the error */
4846 MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
4848 if (G_UNLIKELY (!o))
4849 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
4850 else if (G_UNLIKELY (vtable->klass->has_finalize))
4851 mono_object_register_finalizer (o, error);
4857 * mono_object_new_specific:
4858 * @vtable: the vtable of the object that we want to create
4860 * Returns: A newly created object with class and domain specified
4864 mono_object_new_specific (MonoVTable *vtable)
4867 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
4868 mono_error_raise_exception (&error);
4874 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
4876 MONO_REQ_GC_UNSAFE_MODE;
4880 mono_error_init (error);
4882 /* check for is_com_object for COM Interop */
4883 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
4886 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4889 MonoClass *klass = mono_class_get_activation_services_class ();
4892 mono_class_init (klass);
4894 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4896 mono_error_set_generic_error (error, "System", "NotSupportedException", "Linked away.");
4899 vtable->domain->create_proxy_for_type_method = im;
4902 pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
4903 if (!mono_error_ok (error))
4906 o = mono_runtime_invoke_checked (im, NULL, pa, error);
4907 if (!mono_error_ok (error))
4914 return mono_object_new_alloc_specific_checked (vtable, error);
4918 ves_icall_object_new_specific (MonoVTable *vtable)
4921 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
4922 mono_error_raise_exception (&error);
4928 * mono_object_new_alloc_specific:
4929 * @vtable: virtual table for the object.
4931 * This function allocates a new `MonoObject` with the type derived
4932 * from the @vtable information. If the class of this object has a
4933 * finalizer, then the object will be tracked for finalization.
4935 * This method might raise an exception on errors. Use the
4936 * `mono_object_new_fast_checked` method if you want to manually raise
4939 * Returns: the allocated object.
4942 mono_object_new_alloc_specific (MonoVTable *vtable)
4945 MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
4946 mono_error_raise_exception (&error);
4952 * mono_object_new_alloc_specific_checked:
4953 * @vtable: virtual table for the object.
4954 * @error: holds the error return value.
4956 * This function allocates a new `MonoObject` with the type derived
4957 * from the @vtable information. If the class of this object has a
4958 * finalizer, then the object will be tracked for finalization.
4960 * If there is not enough memory, the @error parameter will be set
4961 * and will contain a user-visible message with the amount of bytes
4962 * that were requested.
4964 * Returns: the allocated object, or NULL if there is not enough memory
4968 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
4970 MONO_REQ_GC_UNSAFE_MODE;
4974 mono_error_init (error);
4976 o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
4978 if (G_UNLIKELY (!o))
4979 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
4980 else if (G_UNLIKELY (vtable->klass->has_finalize))
4981 mono_object_register_finalizer (o, error);
4987 * mono_object_new_fast:
4988 * @vtable: virtual table for the object.
4990 * This function allocates a new `MonoObject` with the type derived
4991 * from the @vtable information. The returned object is not tracked
4992 * for finalization. If your object implements a finalizer, you should
4993 * use `mono_object_new_alloc_specific` instead.
4995 * This method might raise an exception on errors. Use the
4996 * `mono_object_new_fast_checked` method if you want to manually raise
4999 * Returns: the allocated object.
5002 mono_object_new_fast (MonoVTable *vtable)
5005 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5006 mono_error_raise_exception (&error);
5012 * mono_object_new_fast_checked:
5013 * @vtable: virtual table for the object.
5014 * @error: holds the error return value.
5016 * This function allocates a new `MonoObject` with the type derived
5017 * from the @vtable information. The returned object is not tracked
5018 * for finalization. If your object implements a finalizer, you should
5019 * use `mono_object_new_alloc_specific_checked` instead.
5021 * If there is not enough memory, the @error parameter will be set
5022 * and will contain a user-visible message with the amount of bytes
5023 * that were requested.
5025 * Returns: the allocated object, or NULL if there is not enough memory
5029 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
5031 MONO_REQ_GC_UNSAFE_MODE;
5035 mono_error_init (error);
5037 o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5039 if (G_UNLIKELY (!o))
5040 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5046 ves_icall_object_new_fast (MonoVTable *vtable)
5049 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5050 mono_error_raise_exception (&error);
5056 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
5058 MONO_REQ_GC_UNSAFE_MODE;
5062 mono_error_init (error);
5064 o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
5066 if (G_UNLIKELY (!o))
5067 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5068 else if (G_UNLIKELY (vtable->klass->has_finalize))
5069 mono_object_register_finalizer (o, error);
5075 * mono_class_get_allocation_ftn:
5077 * @for_box: the object will be used for boxing
5078 * @pass_size_in_words:
5080 * Return the allocation function appropriate for the given class.
5084 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
5086 MONO_REQ_GC_NEUTRAL_MODE;
5088 *pass_size_in_words = FALSE;
5090 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass) || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
5091 return ves_icall_object_new_specific;
5093 if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
5095 return ves_icall_object_new_fast;
5098 * FIXME: This is actually slower than ves_icall_object_new_fast, because
5099 * of the overhead of parameter passing.
5102 *pass_size_in_words = TRUE;
5103 #ifdef GC_REDIRECT_TO_LOCAL
5104 return GC_local_gcj_fast_malloc;
5106 return GC_gcj_fast_malloc;
5111 return ves_icall_object_new_specific;
5115 * mono_object_new_from_token:
5116 * @image: Context where the type_token is hosted
5117 * @token: a token of the type that we want to create
5119 * Returns: A newly created object whose definition is
5120 * looked up using @token in the @image image
5123 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
5125 MONO_REQ_GC_UNSAFE_MODE;
5131 klass = mono_class_get_checked (image, token, &error);
5132 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
5134 result = mono_object_new_checked (domain, klass, &error);
5136 mono_error_raise_exception (&error); /* FIXME don't raise here */
5143 * mono_object_clone:
5144 * @obj: the object to clone
5146 * Returns: A newly created object who is a shallow copy of @obj
5149 mono_object_clone (MonoObject *obj)
5152 MonoObject *o = mono_object_clone_checked (obj, &error);
5153 mono_error_raise_exception (&error);
5159 mono_object_clone_checked (MonoObject *obj, MonoError *error)
5161 MONO_REQ_GC_UNSAFE_MODE;
5166 mono_error_init (error);
5168 size = obj->vtable->klass->instance_size;
5170 if (obj->vtable->klass->rank)
5171 return (MonoObject*)mono_array_clone ((MonoArray*)obj);
5173 o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
5175 if (G_UNLIKELY (!o)) {
5176 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5180 /* If the object doesn't contain references this will do a simple memmove. */
5181 mono_gc_wbarrier_object_copy (o, obj);
5183 if (obj->vtable->klass->has_finalize)
5184 mono_object_register_finalizer (o, error);
5189 * mono_array_full_copy:
5190 * @src: source array to copy
5191 * @dest: destination array
5193 * Copies the content of one array to another with exactly the same type and size.
5196 mono_array_full_copy (MonoArray *src, MonoArray *dest)
5198 MONO_REQ_GC_UNSAFE_MODE;
5201 MonoClass *klass = src->obj.vtable->klass;
5203 g_assert (klass == dest->obj.vtable->klass);
5205 size = mono_array_length (src);
5206 g_assert (size == mono_array_length (dest));
5207 size *= mono_array_element_size (klass);
5209 if (klass->element_class->valuetype) {
5210 if (klass->element_class->has_references)
5211 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
5213 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5215 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
5218 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5223 * mono_array_clone_in_domain:
5224 * @domain: the domain in which the array will be cloned into
5225 * @array: the array to clone
5227 * This routine returns a copy of the array that is hosted on the
5228 * specified MonoDomain.
5231 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
5233 MONO_REQ_GC_UNSAFE_MODE;
5239 MonoClass *klass = array->obj.vtable->klass;
5241 if (array->bounds == NULL) {
5242 size = mono_array_length (array);
5243 o = mono_array_new_full_checked (domain, klass, &size, NULL, &error);
5244 mono_error_raise_exception (&error); /* FIXME don't raise here */
5246 size *= mono_array_element_size (klass);
5248 if (klass->element_class->valuetype) {
5249 if (klass->element_class->has_references)
5250 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5252 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5254 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5257 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5262 sizes = (uintptr_t *)alloca (klass->rank * sizeof(intptr_t) * 2);
5263 size = mono_array_element_size (klass);
5264 for (i = 0; i < klass->rank; ++i) {
5265 sizes [i] = array->bounds [i].length;
5266 size *= array->bounds [i].length;
5267 sizes [i + klass->rank] = array->bounds [i].lower_bound;
5269 o = mono_array_new_full_checked (domain, klass, sizes, (intptr_t*)sizes + klass->rank, &error);
5270 mono_error_raise_exception (&error); /* FIXME don't raise here */
5272 if (klass->element_class->valuetype) {
5273 if (klass->element_class->has_references)
5274 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5276 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5278 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5281 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5289 * @array: the array to clone
5291 * Returns: A newly created array who is a shallow copy of @array
5294 mono_array_clone (MonoArray *array)
5296 MONO_REQ_GC_UNSAFE_MODE;
5298 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
5301 /* helper macros to check for overflow when calculating the size of arrays */
5302 #ifdef MONO_BIG_ARRAYS
5303 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
5304 #define MYGUINT_MAX MYGUINT64_MAX
5305 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5306 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
5307 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5308 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
5309 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
5311 #define MYGUINT32_MAX 4294967295U
5312 #define MYGUINT_MAX MYGUINT32_MAX
5313 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5314 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
5315 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5316 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
5317 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
5321 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
5323 MONO_REQ_GC_NEUTRAL_MODE;
5327 byte_len = mono_array_element_size (klass);
5328 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
5331 if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
5333 byte_len += MONO_SIZEOF_MONO_ARRAY;
5341 * mono_array_new_full:
5342 * @domain: domain where the object is created
5343 * @array_class: array class
5344 * @lengths: lengths for each dimension in the array
5345 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
5347 * This routine creates a new array objects with the given dimensions,
5348 * lower bounds and type.
5351 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
5354 MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
5355 mono_error_raise_exception (&error);
5361 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
5363 MONO_REQ_GC_UNSAFE_MODE;
5365 uintptr_t byte_len = 0, len, bounds_size;
5368 MonoArrayBounds *bounds;
5372 mono_error_init (error);
5374 if (!array_class->inited)
5375 mono_class_init (array_class);
5379 /* A single dimensional array with a 0 lower bound is the same as an szarray */
5380 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
5382 if (len > MONO_ARRAY_MAX_INDEX) {
5383 mono_error_set_generic_error (error, "System", "OverflowException", "");
5388 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
5390 for (i = 0; i < array_class->rank; ++i) {
5391 if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
5392 mono_error_set_generic_error (error, "System", "OverflowException", "");
5395 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5396 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5403 if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5404 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5410 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5411 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5414 byte_len = (byte_len + 3) & ~3;
5415 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5416 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5419 byte_len += bounds_size;
5422 * Following three lines almost taken from mono_object_new ():
5423 * they need to be kept in sync.
5425 vtable = mono_class_vtable_full (domain, array_class, error);
5426 return_val_if_nok (error, NULL);
5429 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5431 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5433 if (G_UNLIKELY (!o)) {
5434 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", byte_len);
5438 array = (MonoArray*)o;
5440 bounds = array->bounds;
5443 for (i = 0; i < array_class->rank; ++i) {
5444 bounds [i].length = lengths [i];
5446 bounds [i].lower_bound = lower_bounds [i];
5455 * @domain: domain where the object is created
5456 * @eclass: element class
5457 * @n: number of array elements
5459 * This routine creates a new szarray with @n elements of type @eclass.
5462 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5464 MONO_REQ_GC_UNSAFE_MODE;
5470 ac = mono_array_class_get (eclass, 1);
5473 MonoVTable *vtable = mono_class_vtable_full (domain, ac, &error);
5474 mono_error_raise_exception (&error); /* FIXME don't raise here */
5476 arr = mono_array_new_specific_checked (vtable, n, &error);
5477 mono_error_raise_exception (&error); /* FIXME don't raise here */
5483 * mono_array_new_specific:
5484 * @vtable: a vtable in the appropriate domain for an initialized class
5485 * @n: number of array elements
5487 * This routine is a fast alternative to mono_array_new() for code which
5488 * can be sure about the domain it operates in.
5491 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5494 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5495 mono_error_raise_exception (&error); /* FIXME don't raise here */
5501 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
5503 MONO_REQ_GC_UNSAFE_MODE;
5508 mono_error_init (error);
5510 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
5511 mono_error_set_generic_error (error, "System", "OverflowException", "");
5515 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
5516 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5519 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
5521 if (G_UNLIKELY (!o)) {
5522 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", byte_len);
5526 return (MonoArray*)o;
5530 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
5533 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5534 mono_error_raise_exception (&error);
5540 * mono_string_new_utf16:
5541 * @text: a pointer to an utf16 string
5542 * @len: the length of the string
5544 * Returns: A newly created string object which contains @text.
5547 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
5549 MONO_REQ_GC_UNSAFE_MODE;
5552 MonoString *res = NULL;
5553 res = mono_string_new_utf16_checked (domain, text, len, &error);
5554 mono_error_raise_exception (&error);
5560 * mono_string_new_utf16_checked:
5561 * @text: a pointer to an utf16 string
5562 * @len: the length of the string
5563 * @error: written on error.
5565 * Returns: A newly created string object which contains @text.
5566 * On error, returns NULL and sets @error.
5569 mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
5571 MONO_REQ_GC_UNSAFE_MODE;
5575 mono_error_init (error);
5577 s = mono_string_new_size_checked (domain, len, error);
5579 memcpy (mono_string_chars (s), text, len * 2);
5585 * mono_string_new_utf32:
5586 * @text: a pointer to an utf32 string
5587 * @len: the length of the string
5589 * Returns: A newly created string object which contains @text.
5592 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
5594 MONO_REQ_GC_UNSAFE_MODE;
5598 mono_unichar2 *utf16_output = NULL;
5599 gint32 utf16_len = 0;
5600 GError *gerror = NULL;
5601 glong items_written;
5603 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
5606 g_error_free (gerror);
5608 while (utf16_output [utf16_len]) utf16_len++;
5610 s = mono_string_new_size_checked (domain, utf16_len, &error);
5611 mono_error_raise_exception (&error); /* FIXME don't raise here */
5613 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
5615 g_free (utf16_output);
5621 * mono_string_new_size:
5622 * @text: a pointer to an utf16 string
5623 * @len: the length of the string
5625 * Returns: A newly created string object of @len
5628 mono_string_new_size (MonoDomain *domain, gint32 len)
5631 MonoString *str = mono_string_new_size_checked (domain, len, &error);
5632 mono_error_raise_exception (&error);
5638 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
5640 MONO_REQ_GC_UNSAFE_MODE;
5646 mono_error_init (error);
5648 /* check for overflow */
5649 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
5650 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
5654 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
5655 g_assert (size > 0);
5657 vtable = mono_class_vtable (domain, mono_defaults.string_class);
5660 s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
5662 if (G_UNLIKELY (!s)) {
5663 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5671 * mono_string_new_len:
5672 * @text: a pointer to an utf8 string
5673 * @length: number of bytes in @text to consider
5675 * Returns: A newly created string object which contains @text.
5678 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
5680 MONO_REQ_GC_UNSAFE_MODE;
5683 GError *eg_error = NULL;
5684 MonoString *o = NULL;
5686 glong items_written;
5688 mono_error_init (&error);
5690 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
5693 o = mono_string_new_utf16_checked (domain, ut, items_written, &error);
5695 g_error_free (eg_error);
5699 mono_error_raise_exception (&error); /* FIXME don't raise here */
5705 * @text: a pointer to an utf8 string
5707 * Returns: A newly created string object which contains @text.
5709 * This function asserts if it cannot allocate a new string.
5711 * @deprecated Use mono_string_new_checked in new code.
5714 mono_string_new (MonoDomain *domain, const char *text)
5717 MonoString *res = NULL;
5718 res = mono_string_new_checked (domain, text, &error);
5719 mono_error_assert_ok (&error);
5724 * mono_string_new_checked:
5725 * @text: a pointer to an utf8 string
5726 * @merror: set on error
5728 * Returns: A newly created string object which contains @text.
5729 * On error returns NULL and sets @merror.
5732 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
5734 MONO_REQ_GC_UNSAFE_MODE;
5736 GError *eg_error = NULL;
5737 MonoString *o = NULL;
5739 glong items_written;
5742 mono_error_init (error);
5746 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &eg_error);
5749 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
5751 g_error_free (eg_error);
5754 mono_error_raise_exception (error);
5756 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
5761 MonoString *o = NULL;
5763 if (!g_utf8_validate (text, -1, &end)) {
5764 mono_error_set_argument (error, "text", "Not a valid utf8 string");
5768 len = g_utf8_strlen (text, -1);
5769 o = mono_string_new_size_checked (domain, len, error);
5772 str = mono_string_chars (o);
5774 while (text < end) {
5775 *str++ = g_utf8_get_char (text);
5776 text = g_utf8_next_char (text);
5785 * mono_string_new_wrapper:
5786 * @text: pointer to utf8 characters.
5788 * Helper function to create a string object from @text in the current domain.
5791 mono_string_new_wrapper (const char *text)
5793 MONO_REQ_GC_UNSAFE_MODE;
5795 MonoDomain *domain = mono_domain_get ();
5798 return mono_string_new (domain, text);
5805 * @class: the class of the value
5806 * @value: a pointer to the unboxed data
5808 * Returns: A newly created object which contains @value.
5811 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
5813 MONO_REQ_GC_UNSAFE_MODE;
5820 g_assert (klass->valuetype);
5821 if (mono_class_is_nullable (klass))
5822 return mono_nullable_box ((guint8 *)value, klass);
5824 vtable = mono_class_vtable (domain, klass);
5827 size = mono_class_instance_size (klass);
5828 res = mono_object_new_alloc_specific_checked (vtable, &error);
5829 mono_error_raise_exception (&error); /* FIXME don't raise here */
5831 size = size - sizeof (MonoObject);
5834 g_assert (size == mono_class_value_size (klass, NULL));
5835 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
5837 #if NO_UNALIGNED_ACCESS
5838 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5842 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
5845 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
5848 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
5851 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
5854 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5858 if (klass->has_finalize) {
5859 mono_object_register_finalizer (res, &error);
5860 mono_error_raise_exception (&error); /* FIXME don't raise here */
5867 * @dest: destination pointer
5868 * @src: source pointer
5869 * @klass: a valuetype class
5871 * Copy a valuetype from @src to @dest. This function must be used
5872 * when @klass contains references fields.
5875 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
5877 MONO_REQ_GC_UNSAFE_MODE;
5879 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
5883 * mono_value_copy_array:
5884 * @dest: destination array
5885 * @dest_idx: index in the @dest array
5886 * @src: source pointer
5887 * @count: number of items
5889 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
5890 * This function must be used when @klass contains references fields.
5891 * Overlap is handled.
5894 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
5896 MONO_REQ_GC_UNSAFE_MODE;
5898 int size = mono_array_element_size (dest->obj.vtable->klass);
5899 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
5900 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
5901 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
5905 * mono_object_get_domain:
5906 * @obj: object to query
5908 * Returns: the MonoDomain where the object is hosted
5911 mono_object_get_domain (MonoObject *obj)
5913 MONO_REQ_GC_UNSAFE_MODE;
5915 return mono_object_domain (obj);
5919 * mono_object_get_class:
5920 * @obj: object to query
5922 * Use this function to obtain the `MonoClass*` for a given `MonoObject`.
5924 * Returns: the MonoClass of the object.
5927 mono_object_get_class (MonoObject *obj)
5929 MONO_REQ_GC_UNSAFE_MODE;
5931 return mono_object_class (obj);
5934 * mono_object_get_size:
5935 * @o: object to query
5937 * Returns: the size, in bytes, of @o
5940 mono_object_get_size (MonoObject* o)
5942 MONO_REQ_GC_UNSAFE_MODE;
5944 MonoClass* klass = mono_object_class (o);
5945 if (klass == mono_defaults.string_class) {
5946 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
5947 } else if (o->vtable->rank) {
5948 MonoArray *array = (MonoArray*)o;
5949 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
5950 if (array->bounds) {
5953 size += sizeof (MonoArrayBounds) * o->vtable->rank;
5957 return mono_class_instance_size (klass);
5962 * mono_object_unbox:
5963 * @obj: object to unbox
5965 * Returns: a pointer to the start of the valuetype boxed in this
5968 * This method will assert if the object passed is not a valuetype.
5971 mono_object_unbox (MonoObject *obj)
5973 MONO_REQ_GC_UNSAFE_MODE;
5975 /* add assert for valuetypes? */
5976 g_assert (obj->vtable->klass->valuetype);
5977 return ((char*)obj) + sizeof (MonoObject);
5981 * mono_object_isinst:
5983 * @klass: a pointer to a class
5985 * Returns: @obj if @obj is derived from @klass
5988 mono_object_isinst (MonoObject *obj, MonoClass *klass)
5990 MONO_REQ_GC_UNSAFE_MODE;
5993 mono_class_init (klass);
5995 if (mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
5996 return mono_object_isinst_mbyref (obj, klass);
6001 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
6005 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
6007 MONO_REQ_GC_UNSAFE_MODE;
6017 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
6018 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
6022 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
6023 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
6026 MonoClass *oklass = vt->klass;
6027 if (mono_class_is_transparent_proxy (oklass))
6028 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
6030 mono_class_setup_supertypes (klass);
6031 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
6034 #ifndef DISABLE_REMOTING
6035 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
6037 MonoDomain *domain = mono_domain_get ();
6039 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
6040 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
6041 MonoMethod *im = NULL;
6044 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
6046 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6047 im = mono_object_get_virtual_method (rp, im);
6050 pa [0] = mono_type_get_object_checked (domain, &klass->byval_arg, &error);
6051 mono_error_raise_exception (&error); /* FIXME don't raise here */
6054 res = mono_runtime_invoke_checked (im, rp, pa, &error);
6055 mono_error_raise_exception (&error); /* FIXME don't raise here */
6057 if (*(MonoBoolean *) mono_object_unbox(res)) {
6058 /* Update the vtable of the remote type, so it can safely cast to this new type */
6059 mono_upgrade_remote_class (domain, obj, klass);
6063 #endif /* DISABLE_REMOTING */
6068 * mono_object_castclass_mbyref:
6070 * @klass: a pointer to a class
6072 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
6075 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
6077 MONO_REQ_GC_UNSAFE_MODE;
6079 if (!obj) return NULL;
6080 if (mono_object_isinst_mbyref (obj, klass)) return obj;
6082 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
6084 "InvalidCastException"));
6089 MonoDomain *orig_domain;
6095 str_lookup (MonoDomain *domain, gpointer user_data)
6097 MONO_REQ_GC_UNSAFE_MODE;
6099 LDStrInfo *info = (LDStrInfo *)user_data;
6100 if (info->res || domain == info->orig_domain)
6102 info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
6106 mono_string_get_pinned (MonoString *str, MonoError *error)
6108 MONO_REQ_GC_UNSAFE_MODE;
6110 mono_error_init (error);
6112 /* We only need to make a pinned version of a string if this is a moving GC */
6113 if (!mono_gc_is_moving ())
6117 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
6118 news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
6120 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
6121 news->length = mono_string_length (str);
6123 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6129 mono_string_is_interned_lookup (MonoString *str, int insert, MonoError *error)
6131 MONO_REQ_GC_UNSAFE_MODE;
6133 MonoGHashTable *ldstr_table;
6134 MonoString *s, *res;
6137 mono_error_init (error);
6139 domain = ((MonoObject *)str)->vtable->domain;
6140 ldstr_table = domain->ldstr_table;
6142 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6148 /* Allocate outside the lock */
6150 s = mono_string_get_pinned (str, error);
6151 return_val_if_nok (error, NULL);
6154 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6159 mono_g_hash_table_insert (ldstr_table, s, s);
6164 LDStrInfo ldstr_info;
6165 ldstr_info.orig_domain = domain;
6166 ldstr_info.ins = str;
6167 ldstr_info.res = NULL;
6169 mono_domain_foreach (str_lookup, &ldstr_info);
6170 if (ldstr_info.res) {
6172 * the string was already interned in some other domain:
6173 * intern it in the current one as well.
6175 mono_g_hash_table_insert (ldstr_table, str, str);
6185 * mono_string_is_interned:
6186 * @o: String to probe
6188 * Returns whether the string has been interned.
6191 mono_string_is_interned (MonoString *o)
6194 MonoString *result = mono_string_is_interned_lookup (o, FALSE, &error);
6195 /* This function does not fail. */
6196 mono_error_assert_ok (&error);
6201 * mono_string_intern:
6202 * @o: String to intern
6204 * Interns the string passed.
6205 * Returns: The interned string.
6208 mono_string_intern (MonoString *str)
6211 MonoString *result = mono_string_intern_checked (str, &error);
6212 mono_error_assert_ok (&error);
6217 * mono_string_intern_checked:
6218 * @o: String to intern
6219 * @error: set on error.
6221 * Interns the string passed.
6222 * Returns: The interned string. On failure returns NULL and sets @error
6225 mono_string_intern_checked (MonoString *str, MonoError *error)
6227 MONO_REQ_GC_UNSAFE_MODE;
6229 mono_error_init (error);
6231 return mono_string_is_interned_lookup (str, TRUE, error);
6236 * @domain: the domain where the string will be used.
6237 * @image: a metadata context
6238 * @idx: index into the user string table.
6240 * Implementation for the ldstr opcode.
6241 * Returns: a loaded string from the @image/@idx combination.
6244 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
6246 MONO_REQ_GC_UNSAFE_MODE;
6248 if (image->dynamic) {
6249 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
6252 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6253 return NULL; /*FIXME we should probably be raising an exception here*/
6254 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
6259 * mono_ldstr_metadata_sig
6260 * @domain: the domain for the string
6261 * @sig: the signature of a metadata string
6263 * Returns: a MonoString for a string stored in the metadata
6266 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
6268 MONO_REQ_GC_UNSAFE_MODE;
6271 const char *str = sig;
6272 MonoString *o, *interned;
6275 len2 = mono_metadata_decode_blob_size (str, &str);
6278 o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, &error);
6279 mono_error_raise_exception (&error); /* FIXME don't raise here */
6280 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
6283 guint16 *p2 = (guint16*)mono_string_chars (o);
6284 for (i = 0; i < len2; ++i) {
6285 *p2 = GUINT16_FROM_LE (*p2);
6291 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6294 return interned; /* o will get garbage collected */
6296 o = mono_string_get_pinned (o, &error);
6297 mono_error_raise_exception (&error); /* FIXME don't raise here */
6300 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6302 mono_g_hash_table_insert (domain->ldstr_table, o, o);
6312 * mono_string_to_utf8:
6313 * @s: a System.String
6315 * Returns the UTF8 representation for @s.
6316 * The resulting buffer needs to be freed with mono_free().
6318 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
6321 mono_string_to_utf8 (MonoString *s)
6323 MONO_REQ_GC_UNSAFE_MODE;
6326 char *result = mono_string_to_utf8_checked (s, &error);
6328 if (!mono_error_ok (&error))
6329 mono_error_raise_exception (&error);
6334 * mono_string_to_utf8_checked:
6335 * @s: a System.String
6336 * @error: a MonoError.
6338 * Converts a MonoString to its UTF8 representation. May fail; check
6339 * @error to determine whether the conversion was successful.
6340 * The resulting buffer should be freed with mono_free().
6343 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
6345 MONO_REQ_GC_UNSAFE_MODE;
6349 GError *gerror = NULL;
6351 mono_error_init (error);
6357 return g_strdup ("");
6359 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
6361 mono_error_set_argument (error, "string", "%s", gerror->message);
6362 g_error_free (gerror);
6365 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6366 if (s->length > written) {
6367 /* allocate the total length and copy the part of the string that has been converted */
6368 char *as2 = (char *)g_malloc0 (s->length);
6369 memcpy (as2, as, written);
6378 * mono_string_to_utf8_ignore:
6381 * Converts a MonoString to its UTF8 representation. Will ignore
6382 * invalid surrogate pairs.
6383 * The resulting buffer should be freed with mono_free().
6387 mono_string_to_utf8_ignore (MonoString *s)
6389 MONO_REQ_GC_UNSAFE_MODE;
6398 return g_strdup ("");
6400 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
6402 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6403 if (s->length > written) {
6404 /* allocate the total length and copy the part of the string that has been converted */
6405 char *as2 = (char *)g_malloc0 (s->length);
6406 memcpy (as2, as, written);
6415 * mono_string_to_utf8_image_ignore:
6416 * @s: a System.String
6418 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
6421 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
6423 MONO_REQ_GC_UNSAFE_MODE;
6425 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
6429 * mono_string_to_utf8_mp_ignore:
6430 * @s: a System.String
6432 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
6435 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
6437 MONO_REQ_GC_UNSAFE_MODE;
6439 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
6444 * mono_string_to_utf16:
6447 * Return an null-terminated array of the utf-16 chars
6448 * contained in @s. The result must be freed with g_free().
6449 * This is a temporary helper until our string implementation
6450 * is reworked to always include the null terminating char.
6453 mono_string_to_utf16 (MonoString *s)
6455 MONO_REQ_GC_UNSAFE_MODE;
6462 as = (char *)g_malloc ((s->length * 2) + 2);
6463 as [(s->length * 2)] = '\0';
6464 as [(s->length * 2) + 1] = '\0';
6467 return (gunichar2 *)(as);
6470 memcpy (as, mono_string_chars(s), s->length * 2);
6471 return (gunichar2 *)(as);
6475 * mono_string_to_utf32:
6478 * Return an null-terminated array of the UTF-32 (UCS-4) chars
6479 * contained in @s. The result must be freed with g_free().
6482 mono_string_to_utf32 (MonoString *s)
6484 MONO_REQ_GC_UNSAFE_MODE;
6486 mono_unichar4 *utf32_output = NULL;
6487 GError *error = NULL;
6488 glong items_written;
6493 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
6496 g_error_free (error);
6498 return utf32_output;
6502 * mono_string_from_utf16:
6503 * @data: the UTF16 string (LPWSTR) to convert
6505 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
6507 * Returns: a MonoString.
6510 mono_string_from_utf16 (gunichar2 *data)
6512 MONO_REQ_GC_UNSAFE_MODE;
6515 MonoString *res = NULL;
6516 MonoDomain *domain = mono_domain_get ();
6522 while (data [len]) len++;
6524 res = mono_string_new_utf16_checked (domain, data, len, &error);
6525 mono_error_raise_exception (&error); /* FIXME don't raise here */
6530 * mono_string_from_utf32:
6531 * @data: the UTF32 string (LPWSTR) to convert
6533 * Converts a UTF32 (UCS-4)to a MonoString.
6535 * Returns: a MonoString.
6538 mono_string_from_utf32 (mono_unichar4 *data)
6540 MONO_REQ_GC_UNSAFE_MODE;
6542 MonoString* result = NULL;
6543 mono_unichar2 *utf16_output = NULL;
6544 GError *error = NULL;
6545 glong items_written;
6551 while (data [len]) len++;
6553 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &error);
6556 g_error_free (error);
6558 result = mono_string_from_utf16 (utf16_output);
6559 g_free (utf16_output);
6564 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
6566 MONO_REQ_GC_UNSAFE_MODE;
6573 r = mono_string_to_utf8_ignore (s);
6575 r = mono_string_to_utf8_checked (s, error);
6576 if (!mono_error_ok (error))
6583 len = strlen (r) + 1;
6585 mp_s = (char *)mono_mempool_alloc (mp, len);
6587 mp_s = (char *)mono_image_alloc (image, len);
6589 memcpy (mp_s, r, len);
6597 * mono_string_to_utf8_image:
6598 * @s: a System.String
6600 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
6603 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
6605 MONO_REQ_GC_UNSAFE_MODE;
6607 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
6611 * mono_string_to_utf8_mp:
6612 * @s: a System.String
6614 * Same as mono_string_to_utf8, but allocate the string from a mempool.
6617 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
6619 MONO_REQ_GC_UNSAFE_MODE;
6621 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
6625 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
6628 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
6630 eh_callbacks = *cbs;
6633 MonoRuntimeExceptionHandlingCallbacks *
6634 mono_get_eh_callbacks (void)
6636 return &eh_callbacks;
6640 * mono_raise_exception:
6641 * @ex: exception object
6643 * Signal the runtime that the exception @ex has been raised in unmanaged code.
6646 mono_raise_exception (MonoException *ex)
6648 MONO_REQ_GC_UNSAFE_MODE;
6651 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
6652 * that will cause gcc to omit the function epilog, causing problems when
6653 * the JIT tries to walk the stack, since the return address on the stack
6654 * will point into the next function in the executable, not this one.
6656 eh_callbacks.mono_raise_exception (ex);
6660 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
6662 MONO_REQ_GC_UNSAFE_MODE;
6664 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
6668 * mono_wait_handle_new:
6669 * @domain: Domain where the object will be created
6670 * @handle: Handle for the wait handle
6672 * Returns: A new MonoWaitHandle created in the given domain for the given handle
6675 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
6677 MONO_REQ_GC_UNSAFE_MODE;
6680 MonoWaitHandle *res;
6681 gpointer params [1];
6682 static MonoMethod *handle_set;
6684 res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, &error);
6685 mono_error_raise_exception (&error); /* FIXME don't raise here */
6687 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
6689 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
6691 params [0] = &handle;
6693 mono_runtime_invoke_checked (handle_set, res, params, &error);
6694 mono_error_raise_exception (&error); /* FIXME don't raise here */
6700 mono_wait_handle_get_handle (MonoWaitHandle *handle)
6702 MONO_REQ_GC_UNSAFE_MODE;
6704 static MonoClassField *f_safe_handle = NULL;
6707 if (!f_safe_handle) {
6708 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safeWaitHandle");
6709 g_assert (f_safe_handle);
6712 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
6718 mono_runtime_capture_context (MonoDomain *domain)
6720 MONO_REQ_GC_UNSAFE_MODE;
6722 RuntimeInvokeFunction runtime_invoke;
6724 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
6725 MonoMethod *method = mono_get_context_capture_method ();
6726 MonoMethod *wrapper;
6729 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
6730 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
6731 domain->capture_context_method = mono_compile_method (method);
6734 runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
6736 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
6739 * mono_async_result_new:
6740 * @domain:domain where the object will be created.
6741 * @handle: wait handle.
6742 * @state: state to pass to AsyncResult
6743 * @data: C closure data.
6745 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
6746 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
6750 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
6752 MONO_REQ_GC_UNSAFE_MODE;
6755 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, &error);
6756 mono_error_raise_exception (&error); /* FIXME don't raise here */
6757 MonoObject *context = mono_runtime_capture_context (domain);
6758 /* we must capture the execution context from the original thread */
6760 MONO_OBJECT_SETREF (res, execution_context, context);
6761 /* note: result may be null if the flow is suppressed */
6764 res->data = (void **)data;
6765 MONO_OBJECT_SETREF (res, object_data, object_data);
6766 MONO_OBJECT_SETREF (res, async_state, state);
6768 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
6770 res->sync_completed = FALSE;
6771 res->completed = FALSE;
6777 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
6779 MONO_REQ_GC_UNSAFE_MODE;
6786 g_assert (ares->async_delegate);
6788 ac = (MonoAsyncCall*) ares->object_data;
6790 res = mono_runtime_delegate_invoke (ares->async_delegate, (void**) &ares->async_state, NULL);
6792 gpointer wait_event = NULL;
6794 ac->msg->exc = NULL;
6795 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args);
6796 MONO_OBJECT_SETREF (ac, res, res);
6798 mono_monitor_enter ((MonoObject*) ares);
6799 ares->completed = 1;
6801 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
6802 mono_monitor_exit ((MonoObject*) ares);
6804 if (wait_event != NULL)
6805 SetEvent (wait_event);
6807 if (ac->cb_method) {
6808 mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
6809 mono_error_raise_exception (&error);
6817 mono_message_init (MonoDomain *domain,
6818 MonoMethodMessage *this_obj,
6819 MonoReflectionMethod *method,
6820 MonoArray *out_args)
6822 MONO_REQ_GC_UNSAFE_MODE;
6824 static MonoClass *object_array_klass;
6825 static MonoClass *byte_array_klass;
6826 static MonoClass *string_array_klass;
6828 MonoMethodSignature *sig = mono_method_signature (method->method);
6835 if (!object_array_klass) {
6838 klass = mono_array_class_get (mono_defaults.byte_class, 1);
6840 byte_array_klass = klass;
6842 klass = mono_array_class_get (mono_defaults.string_class, 1);
6844 string_array_klass = klass;
6846 klass = mono_array_class_get (mono_defaults.object_class, 1);
6849 mono_atomic_store_release (&object_array_klass, klass);
6852 MONO_OBJECT_SETREF (this_obj, method, method);
6854 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), sig->param_count, &error);
6855 mono_error_raise_exception (&error); /* FIXME don't raise here */
6857 MONO_OBJECT_SETREF (this_obj, args, arr);
6859 arr = mono_array_new_specific_checked (mono_class_vtable (domain, byte_array_klass), sig->param_count, &error);
6860 mono_error_raise_exception (&error); /* FIXME don't raise here */
6862 MONO_OBJECT_SETREF (this_obj, arg_types, arr);
6864 this_obj->async_result = NULL;
6865 this_obj->call_type = CallType_Sync;
6867 names = g_new (char *, sig->param_count);
6868 mono_method_get_param_names (method->method, (const char **) names);
6870 arr = mono_array_new_specific_checked (mono_class_vtable (domain, string_array_klass), sig->param_count, &error);
6871 mono_error_raise_exception (&error); /* FIXME don't raise here */
6873 MONO_OBJECT_SETREF (this_obj, names, arr);
6875 for (i = 0; i < sig->param_count; i++) {
6876 name = mono_string_new (domain, names [i]);
6877 mono_array_setref (this_obj->names, i, name);
6881 for (i = 0, j = 0; i < sig->param_count; i++) {
6882 if (sig->params [i]->byref) {
6884 MonoObject* arg = (MonoObject *)mono_array_get (out_args, gpointer, j);
6885 mono_array_setref (this_obj->args, i, arg);
6889 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
6893 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
6896 mono_array_set (this_obj->arg_types, guint8, i, arg_type);
6900 #ifndef DISABLE_REMOTING
6902 * mono_remoting_invoke:
6903 * @real_proxy: pointer to a RealProxy object
6904 * @msg: The MonoMethodMessage to execute
6905 * @exc: used to store exceptions
6906 * @out_args: used to store output arguments
6908 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
6909 * IMessage interface and it is not trivial to extract results from there. So
6910 * we call an helper method PrivateInvoke instead of calling
6911 * RealProxy::Invoke() directly.
6913 * Returns: the result object.
6916 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, MonoObject **exc, MonoArray **out_args, MonoError *error)
6918 MONO_REQ_GC_UNSAFE_MODE;
6921 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
6926 mono_error_init (error);
6928 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
6931 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
6933 mono_error_set_generic_error (error, "System", "NotSupportedException", "Linked away.");
6936 real_proxy->vtable->domain->private_invoke_method = im;
6939 pa [0] = real_proxy;
6944 o = mono_runtime_try_invoke (im, NULL, pa, exc, error);
6945 return_val_if_nok (error, NULL);
6952 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
6953 MonoObject **exc, MonoArray **out_args)
6955 MONO_REQ_GC_UNSAFE_MODE;
6957 static MonoClass *object_array_klass;
6961 MonoMethodSignature *sig;
6964 int i, j, outarg_count = 0;
6966 #ifndef DISABLE_REMOTING
6967 if (target && mono_object_is_transparent_proxy (target)) {
6968 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
6969 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6970 target = tp->rp->unwrapped_server;
6972 ret = mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args, &error);
6973 mono_error_raise_exception (&error); /* FIXME don't raise here */
6980 domain = mono_domain_get ();
6981 method = msg->method->method;
6982 sig = mono_method_signature (method);
6984 for (i = 0; i < sig->param_count; i++) {
6985 if (sig->params [i]->byref)
6989 if (!object_array_klass) {
6992 klass = mono_array_class_get (mono_defaults.object_class, 1);
6995 mono_memory_barrier ();
6996 object_array_klass = klass;
6999 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, &error);
7000 mono_error_raise_exception (&error); /* FIXME don't raise here */
7002 mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
7005 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
7007 for (i = 0, j = 0; i < sig->param_count; i++) {
7008 if (sig->params [i]->byref) {
7010 arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
7011 mono_array_setref (*out_args, j, arg);
7020 * mono_object_to_string:
7022 * @exc: Any exception thrown by ToString (). May be NULL.
7024 * Returns: the result of calling ToString () on an object.
7027 mono_object_to_string (MonoObject *obj, MonoObject **exc)
7029 MONO_REQ_GC_UNSAFE_MODE;
7031 static MonoMethod *to_string = NULL;
7040 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
7042 method = mono_object_get_virtual_method (obj, to_string);
7044 // Unbox value type if needed
7045 if (mono_class_is_valuetype (mono_method_get_class (method))) {
7046 target = mono_object_unbox (obj);
7050 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
7051 if (*exc == NULL && !mono_error_ok (&error))
7052 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
7054 mono_error_cleanup (&error);
7056 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
7057 mono_error_raise_exception (&error); /* FIXME don't raise here */
7064 * mono_print_unhandled_exception:
7065 * @exc: The exception
7067 * Prints the unhandled exception.
7070 mono_print_unhandled_exception (MonoObject *exc)
7072 MONO_REQ_GC_UNSAFE_MODE;
7075 char *message = (char*)"";
7076 gboolean free_message = FALSE;
7079 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
7080 message = g_strdup ("OutOfMemoryException");
7081 free_message = TRUE;
7082 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
7083 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
7084 free_message = TRUE;
7087 if (((MonoException*)exc)->native_trace_ips) {
7088 message = mono_exception_get_native_backtrace ((MonoException*)exc);
7089 free_message = TRUE;
7091 MonoObject *other_exc = NULL;
7092 str = mono_object_to_string (exc, &other_exc);
7094 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
7095 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
7097 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
7098 original_backtrace, nested_backtrace);
7100 g_free (original_backtrace);
7101 g_free (nested_backtrace);
7102 free_message = TRUE;
7104 message = mono_string_to_utf8_checked (str, &error);
7105 if (!mono_error_ok (&error)) {
7106 mono_error_cleanup (&error);
7107 message = (char *) "";
7109 free_message = TRUE;
7116 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
7117 * exc->vtable->klass->name, message);
7119 g_printerr ("\nUnhandled Exception:\n%s\n", message);
7126 * mono_delegate_ctor:
7127 * @this: pointer to an uninitialized delegate object
7128 * @target: target object
7129 * @addr: pointer to native code
7132 * Initialize a delegate and sets a specific method, not the one
7133 * associated with addr. This is useful when sharing generic code.
7134 * In that case addr will most probably not be associated with the
7135 * correct instantiation of the method.
7138 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method)
7140 MONO_REQ_GC_UNSAFE_MODE;
7142 MonoDelegate *delegate = (MonoDelegate *)this_obj;
7144 g_assert (this_obj);
7147 g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
7150 delegate->method = method;
7152 mono_stats.delegate_creations++;
7154 #ifndef DISABLE_REMOTING
7155 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
7157 method = mono_marshal_get_remoting_invoke (method);
7158 delegate->method_ptr = mono_compile_method (method);
7159 MONO_OBJECT_SETREF (delegate, target, target);
7163 delegate->method_ptr = addr;
7164 MONO_OBJECT_SETREF (delegate, target, target);
7167 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
7168 if (callbacks.init_delegate)
7169 callbacks.init_delegate (delegate);
7173 * mono_delegate_ctor:
7174 * @this: pointer to an uninitialized delegate object
7175 * @target: target object
7176 * @addr: pointer to native code
7178 * This is used to initialize a delegate.
7181 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr)
7183 MONO_REQ_GC_UNSAFE_MODE;
7185 MonoDomain *domain = mono_domain_get ();
7187 MonoMethod *method = NULL;
7191 ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
7193 if (!ji && domain != mono_get_root_domain ())
7194 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
7196 method = mono_jit_info_get_method (ji);
7197 g_assert (!method->klass->generic_container);
7200 mono_delegate_ctor_with_method (this_obj, target, addr, method);
7204 * mono_method_call_message_new:
7205 * @method: method to encapsulate
7206 * @params: parameters to the method
7207 * @invoke: optional, delegate invoke.
7208 * @cb: async callback delegate.
7209 * @state: state passed to the async callback.
7211 * Translates arguments pointers into a MonoMethodMessage.
7214 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
7215 MonoDelegate **cb, MonoObject **state)
7217 MONO_REQ_GC_UNSAFE_MODE;
7221 MonoDomain *domain = mono_domain_get ();
7222 MonoMethodSignature *sig = mono_method_signature (method);
7223 MonoMethodMessage *msg;
7226 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7227 mono_error_raise_exception (&error); /* FIXME don't raise here */
7230 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, &error);
7231 mono_error_raise_exception (&error); /* FIXME don't raise here */
7232 mono_message_init (domain, msg, rm, NULL);
7233 count = sig->param_count - 2;
7235 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, &error);
7236 mono_error_raise_exception (&error); /* FIXME don't raise here */
7237 mono_message_init (domain, msg, rm, NULL);
7238 count = sig->param_count;
7241 for (i = 0; i < count; i++) {
7246 if (sig->params [i]->byref)
7247 vpos = *((gpointer *)params [i]);
7251 klass = mono_class_from_mono_type (sig->params [i]);
7253 if (klass->valuetype)
7254 arg = mono_value_box (domain, klass, vpos);
7256 arg = *((MonoObject **)vpos);
7258 mono_array_setref (msg->args, i, arg);
7261 if (cb != NULL && state != NULL) {
7262 *cb = *((MonoDelegate **)params [i]);
7264 *state = *((MonoObject **)params [i]);
7271 * mono_method_return_message_restore:
7273 * Restore results from message based processing back to arguments pointers
7276 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
7278 MONO_REQ_GC_UNSAFE_MODE;
7280 MonoMethodSignature *sig = mono_method_signature (method);
7281 int i, j, type, size, out_len;
7283 if (out_args == NULL)
7285 out_len = mono_array_length (out_args);
7289 for (i = 0, j = 0; i < sig->param_count; i++) {
7290 MonoType *pt = sig->params [i];
7295 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
7297 arg = (char *)mono_array_get (out_args, gpointer, j);
7300 g_assert (type != MONO_TYPE_VOID);
7302 if (MONO_TYPE_IS_REFERENCE (pt)) {
7303 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
7306 MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
7307 size = mono_class_value_size (klass, NULL);
7308 if (klass->has_references)
7309 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
7311 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
7313 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
7314 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
7323 #ifndef DISABLE_REMOTING
7326 * mono_load_remote_field:
7327 * @this: pointer to an object
7328 * @klass: klass of the object containing @field
7329 * @field: the field to load
7330 * @res: a storage to store the result
7332 * This method is called by the runtime on attempts to load fields of
7333 * transparent proxy objects. @this points to such TP, @klass is the class of
7334 * the object containing @field. @res is a storage location which can be
7335 * used to store the result.
7337 * Returns: an address pointing to the value of field.
7340 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
7342 MONO_REQ_GC_UNSAFE_MODE;
7346 static MonoMethod *getter = NULL;
7347 MonoDomain *domain = mono_domain_get ();
7348 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7349 MonoClass *field_class;
7350 MonoMethodMessage *msg;
7351 MonoArray *out_args;
7355 g_assert (mono_object_is_transparent_proxy (this_obj));
7356 g_assert (res != NULL);
7358 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7359 mono_field_get_value (tp->rp->unwrapped_server, field, res);
7364 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
7366 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7369 field_class = mono_class_from_mono_type (field->type);
7371 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7372 mono_error_raise_exception (&error); /* FIXME don't raise here */
7373 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
7374 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, &error);
7375 mono_error_raise_exception (&error); /* FIXME don't raise here */
7376 mono_message_init (domain, msg, rm, out_args);
7378 full_name = mono_type_get_full_name (klass);
7379 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7380 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7383 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, &error);
7384 mono_error_raise_exception (&error); /* FIXME don't raise here */
7386 if (exc) mono_raise_exception ((MonoException *)exc);
7388 if (mono_array_length (out_args) == 0)
7391 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
7393 if (field_class->valuetype) {
7394 return ((char *)*res) + sizeof (MonoObject);
7400 * mono_load_remote_field_new:
7405 * Missing documentation.
7408 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
7410 MONO_REQ_GC_UNSAFE_MODE;
7414 static MonoMethod *getter = NULL;
7415 MonoDomain *domain = mono_domain_get ();
7416 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7417 MonoClass *field_class;
7418 MonoMethodMessage *msg;
7419 MonoArray *out_args;
7420 MonoObject *exc, *res;
7423 g_assert (mono_object_is_transparent_proxy (this_obj));
7425 field_class = mono_class_from_mono_type (field->type);
7427 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7429 if (field_class->valuetype) {
7430 res = mono_object_new_checked (domain, field_class, &error);
7431 mono_error_raise_exception (&error); /* FIXME don't raise here */
7432 val = ((gchar *) res) + sizeof (MonoObject);
7436 mono_field_get_value (tp->rp->unwrapped_server, field, val);
7441 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
7443 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7446 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7447 mono_error_raise_exception (&error); /* FIXME don't raise here */
7448 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
7450 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, &error);
7451 mono_error_raise_exception (&error); /* FIXME don't raise here */
7452 mono_message_init (domain, msg, rm, out_args);
7454 full_name = mono_type_get_full_name (klass);
7455 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7456 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7459 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, &error);
7460 mono_error_raise_exception (&error); /* FIXME don't raise here */
7462 if (exc) mono_raise_exception ((MonoException *)exc);
7464 if (mono_array_length (out_args) == 0)
7467 res = mono_array_get (out_args, MonoObject *, 0);
7473 * mono_store_remote_field:
7474 * @this_obj: pointer to an object
7475 * @klass: klass of the object containing @field
7476 * @field: the field to load
7477 * @val: the value/object to store
7479 * This method is called by the runtime on attempts to store fields of
7480 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
7481 * the object containing @field. @val is the new value to store in @field.
7484 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
7486 MONO_REQ_GC_UNSAFE_MODE;
7490 static MonoMethod *setter = NULL;
7491 MonoDomain *domain = mono_domain_get ();
7492 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7493 MonoClass *field_class;
7494 MonoMethodMessage *msg;
7495 MonoArray *out_args;
7500 g_assert (mono_object_is_transparent_proxy (this_obj));
7502 field_class = mono_class_from_mono_type (field->type);
7504 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7505 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
7506 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
7511 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
7513 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7516 if (field_class->valuetype)
7517 arg = mono_value_box (domain, field_class, val);
7519 arg = *((MonoObject **)val);
7522 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7523 mono_error_raise_exception (&error); /* FIXME don't raise here */
7524 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, setter, NULL, &error);
7525 mono_error_raise_exception (&error); /* FIXME don't raise here */
7526 mono_message_init (domain, msg, rm, NULL);
7528 full_name = mono_type_get_full_name (klass);
7529 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7530 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7531 mono_array_setref (msg->args, 2, arg);
7534 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, &error);
7535 mono_error_raise_exception (&error); /* FIXME don't raise here */
7537 if (exc) mono_raise_exception ((MonoException *)exc);
7541 * mono_store_remote_field_new:
7547 * Missing documentation
7550 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
7552 MONO_REQ_GC_UNSAFE_MODE;
7556 static MonoMethod *setter = NULL;
7557 MonoDomain *domain = mono_domain_get ();
7558 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7559 MonoClass *field_class;
7560 MonoMethodMessage *msg;
7561 MonoArray *out_args;
7565 g_assert (mono_object_is_transparent_proxy (this_obj));
7567 field_class = mono_class_from_mono_type (field->type);
7569 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7570 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
7571 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
7576 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
7578 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7581 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7582 mono_error_raise_exception (&error); /* FIXME don't raise here */
7583 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, setter, NULL, &error);
7584 mono_error_raise_exception (&error); /* FIXME don't raise here */
7585 mono_message_init (domain, msg, rm, NULL);
7587 full_name = mono_type_get_full_name (klass);
7588 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7589 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7590 mono_array_setref (msg->args, 2, arg);
7593 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, &error);
7594 mono_error_raise_exception (&error); /* FIXME don't raise here */
7596 if (exc) mono_raise_exception ((MonoException *)exc);
7601 * mono_create_ftnptr:
7603 * Given a function address, create a function descriptor for it.
7604 * This is only needed on some platforms.
7607 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
7609 return callbacks.create_ftnptr (domain, addr);
7613 * mono_get_addr_from_ftnptr:
7615 * Given a pointer to a function descriptor, return the function address.
7616 * This is only needed on some platforms.
7619 mono_get_addr_from_ftnptr (gpointer descr)
7621 return callbacks.get_addr_from_ftnptr (descr);
7625 * mono_string_chars:
7628 * Returns a pointer to the UCS16 characters stored in the MonoString
7631 mono_string_chars (MonoString *s)
7633 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
7639 * mono_string_length:
7642 * Returns the lenght in characters of the string
7645 mono_string_length (MonoString *s)
7647 MONO_REQ_GC_UNSAFE_MODE;
7653 * mono_array_length:
7654 * @array: a MonoArray*
7656 * Returns the total number of elements in the array. This works for
7657 * both vectors and multidimensional arrays.
7660 mono_array_length (MonoArray *array)
7662 MONO_REQ_GC_UNSAFE_MODE;
7664 return array->max_length;
7668 * mono_array_addr_with_size:
7669 * @array: a MonoArray*
7670 * @size: size of the array elements
7671 * @idx: index into the array
7673 * Use this function to obtain the address for the @idx item on the
7674 * @array containing elements of size @size.
7676 * This method performs no bounds checking or type checking.
7678 * Returns the address of the @idx element in the array.
7681 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
7683 MONO_REQ_GC_UNSAFE_MODE;
7685 return ((char*)(array)->vector) + size * idx;
7690 mono_glist_to_array (GList *list, MonoClass *eclass)
7692 MonoDomain *domain = mono_domain_get ();
7699 len = g_list_length (list);
7700 res = mono_array_new (domain, eclass, len);
7702 for (i = 0; list; list = list->next, i++)
7703 mono_array_set (res, gpointer, i, list->data);
7710 * The following section is purely to declare prototypes and
7711 * document the API, as these C files are processed by our
7717 * @array: array to alter
7718 * @element_type: A C type name, this macro will use the sizeof(type) to determine the element size
7719 * @index: index into the array
7720 * @value: value to set
7722 * Value Type version: This sets the @index's element of the @array
7723 * with elements of size sizeof(type) to the provided @value.
7725 * This macro does not attempt to perform type checking or bounds checking.
7727 * Use this to set value types in a `MonoArray`.
7729 void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
7734 * mono_array_setref:
7735 * @array: array to alter
7736 * @index: index into the array
7737 * @value: value to set
7739 * Reference Type version: This sets the @index's element of the
7740 * @array with elements of size sizeof(type) to the provided @value.
7742 * This macro does not attempt to perform type checking or bounds checking.
7744 * Use this to reference types in a `MonoArray`.
7746 void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
7752 * @array: array on which to operate on
7753 * @element_type: C element type (example: MonoString *, int, MonoObject *)
7754 * @index: index into the array
7756 * Use this macro to retrieve the @index element of an @array and
7757 * extract the value assuming that the elements of the array match
7758 * the provided type value.
7760 * This method can be used with both arrays holding value types and
7761 * reference types. For reference types, the @type parameter should
7762 * be a `MonoObject*` or any subclass of it, like `MonoString*`.
7764 * This macro does not attempt to perform type checking or bounds checking.
7766 * Returns: The element at the @index position in the @array.
7768 Type mono_array_get (MonoArray *array, Type element_type, uintptr_t index)