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/domain-internals.h>
27 #include "mono/metadata/metadata-internals.h"
28 #include "mono/metadata/class-internals.h"
29 #include <mono/metadata/assembly.h>
30 #include <mono/metadata/marshal.h>
31 #include "mono/metadata/debug-helpers.h"
32 #include "mono/metadata/marshal.h"
33 #include <mono/metadata/threads.h>
34 #include <mono/metadata/threads-types.h>
35 #include <mono/metadata/environment.h>
36 #include "mono/metadata/profiler-private.h"
37 #include "mono/metadata/security-manager.h"
38 #include "mono/metadata/mono-debug-debugger.h"
39 #include <mono/metadata/gc-internals.h>
40 #include <mono/metadata/verify-internals.h>
41 #include <mono/metadata/reflection-internals.h>
42 #include <mono/utils/strenc.h>
43 #include <mono/utils/mono-counters.h>
44 #include <mono/utils/mono-error-internals.h>
45 #include <mono/utils/mono-memory-model.h>
46 #include <mono/utils/checked-build.h>
47 #include <mono/utils/mono-threads.h>
48 #include "cominterop.h"
51 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value);
54 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig);
57 free_main_args (void);
60 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error);
62 /* Class lazy loading functions */
63 static GENERATE_GET_CLASS_WITH_CACHE (pointer, System.Reflection, Pointer)
64 static GENERATE_GET_CLASS_WITH_CACHE (remoting_services, System.Runtime.Remoting, RemotingServices)
65 static GENERATE_GET_CLASS_WITH_CACHE (unhandled_exception_event_args, System, UnhandledExceptionEventArgs)
66 static GENERATE_GET_CLASS_WITH_CACHE (sta_thread_attribute, System, STAThreadAttribute)
67 static GENERATE_GET_CLASS_WITH_CACHE (activation_services, System.Runtime.Remoting.Activation, ActivationServices)
70 #define ldstr_lock() mono_os_mutex_lock (&ldstr_section)
71 #define ldstr_unlock() mono_os_mutex_unlock (&ldstr_section)
72 static mono_mutex_t ldstr_section;
75 mono_runtime_object_init (MonoObject *this_obj)
77 MONO_REQ_GC_UNSAFE_MODE;
80 MonoMethod *method = NULL;
81 MonoClass *klass = this_obj->vtable->klass;
83 method = mono_class_get_method_from_name (klass, ".ctor", 0);
85 g_error ("Could not lookup zero argument constructor for class %s", mono_type_get_full_name (klass));
87 if (method->klass->valuetype)
88 this_obj = (MonoObject *)mono_object_unbox (this_obj);
90 mono_runtime_invoke_checked (method, this_obj, NULL, &error);
91 mono_error_raise_exception (&error); /* FIXME don't raise here */
94 /* The pseudo algorithm for type initialization from the spec
95 Note it doesn't say anything about domains - only threads.
97 2. If the type is initialized you are done.
98 2.1. If the type is not yet initialized, try to take an
100 2.2. If successful, record this thread as responsible for
101 initializing the type and proceed to step 2.3.
102 2.2.1. If not, see whether this thread or any thread
103 waiting for this thread to complete already holds the lock.
104 2.2.2. If so, return since blocking would create a deadlock. This thread
105 will now see an incompletely initialized state for the type,
106 but no deadlock will arise.
107 2.2.3 If not, block until the type is initialized then return.
108 2.3 Initialize the parent type and then all interfaces implemented
110 2.4 Execute the type initialization code for this type.
111 2.5 Mark the type as initialized, release the initialization lock,
112 awaken any threads waiting for this type to be initialized,
119 MonoNativeThreadId initializing_tid;
120 guint32 waiting_count;
122 MonoCoopMutex initialization_section;
123 } TypeInitializationLock;
125 /* for locking access to type_initialization_hash and blocked_thread_hash */
126 static MonoCoopMutex type_initialization_section;
129 mono_type_initialization_lock (void)
131 /* The critical sections protected by this lock in mono_runtime_class_init_full () can block */
132 mono_coop_mutex_lock (&type_initialization_section);
136 mono_type_initialization_unlock (void)
138 mono_coop_mutex_unlock (&type_initialization_section);
142 mono_type_init_lock (TypeInitializationLock *lock)
144 MONO_REQ_GC_NEUTRAL_MODE;
146 mono_coop_mutex_lock (&lock->initialization_section);
150 mono_type_init_unlock (TypeInitializationLock *lock)
152 mono_coop_mutex_unlock (&lock->initialization_section);
155 /* from vtable to lock */
156 static GHashTable *type_initialization_hash;
158 /* from thread id to thread id being waited on */
159 static GHashTable *blocked_thread_hash;
162 static MonoThread *main_thread;
164 /* Functions supplied by the runtime */
165 static MonoRuntimeCallbacks callbacks;
168 * mono_thread_set_main:
169 * @thread: thread to set as the main thread
171 * This function can be used to instruct the runtime to treat @thread
172 * as the main thread, ie, the thread that would normally execute the Main()
173 * method. This basically means that at the end of @thread, the runtime will
174 * wait for the existing foreground threads to quit and other such details.
177 mono_thread_set_main (MonoThread *thread)
179 MONO_REQ_GC_UNSAFE_MODE;
181 static gboolean registered = FALSE;
184 MONO_GC_REGISTER_ROOT_SINGLE (main_thread, MONO_ROOT_SOURCE_THREADING, "main thread object");
188 main_thread = thread;
192 mono_thread_get_main (void)
194 MONO_REQ_GC_UNSAFE_MODE;
200 mono_type_initialization_init (void)
202 mono_coop_mutex_init_recursive (&type_initialization_section);
203 type_initialization_hash = g_hash_table_new (NULL, NULL);
204 blocked_thread_hash = g_hash_table_new (NULL, NULL);
205 mono_os_mutex_init_recursive (&ldstr_section);
209 mono_type_initialization_cleanup (void)
212 /* This is causing race conditions with
213 * mono_release_type_locks
215 mono_coop_mutex_destroy (&type_initialization_section);
216 g_hash_table_destroy (type_initialization_hash);
217 type_initialization_hash = NULL;
219 mono_os_mutex_destroy (&ldstr_section);
220 g_hash_table_destroy (blocked_thread_hash);
221 blocked_thread_hash = NULL;
227 * get_type_init_exception_for_vtable:
229 * Return the stored type initialization exception for VTABLE.
231 static MonoException*
232 get_type_init_exception_for_vtable (MonoVTable *vtable)
234 MONO_REQ_GC_UNSAFE_MODE;
236 MonoDomain *domain = vtable->domain;
237 MonoClass *klass = vtable->klass;
241 if (!vtable->init_failed)
242 g_error ("Trying to get the init exception for a non-failed vtable of class %s", mono_type_get_full_name (klass));
245 * If the initializing thread was rudely aborted, the exception is not stored
249 mono_domain_lock (domain);
250 if (domain->type_init_exception_hash)
251 ex = (MonoException *)mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
252 mono_domain_unlock (domain);
255 if (klass->name_space && *klass->name_space)
256 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
258 full_name = g_strdup (klass->name);
259 ex = mono_get_exception_type_initialization (full_name, NULL);
266 * mono_runtime_class_init:
267 * @vtable: vtable that needs to be initialized
269 * This routine calls the class constructor for @vtable.
272 mono_runtime_class_init (MonoVTable *vtable)
274 MONO_REQ_GC_UNSAFE_MODE;
276 mono_runtime_class_init_full (vtable, TRUE);
280 * mono_runtime_class_init_full:
281 * @vtable that neeeds to be initialized
282 * @raise_exception is TRUE, exceptions are raised intead of returned
286 mono_runtime_class_init_full (MonoVTable *vtable, gboolean raise_exception)
288 MONO_REQ_GC_UNSAFE_MODE;
292 MonoException *exc_to_throw;
293 MonoMethod *method = NULL;
296 MonoDomain *domain = vtable->domain;
297 TypeInitializationLock *lock;
298 MonoNativeThreadId tid;
299 int do_initialization = 0;
300 MonoDomain *last_domain = NULL;
302 if (vtable->initialized)
306 klass = vtable->klass;
308 if (!klass->image->checked_module_cctor) {
309 mono_image_check_for_module_cctor (klass->image);
310 if (klass->image->has_module_cctor) {
312 MonoClass *module_klass;
313 MonoVTable *module_vtable;
315 module_klass = mono_class_get_checked (klass->image, MONO_TOKEN_TYPE_DEF | 1, &error);
317 exc = mono_error_convert_to_exception (&error);
319 mono_raise_exception (exc);
323 module_vtable = mono_class_vtable_full (vtable->domain, module_klass, raise_exception);
326 exc = mono_runtime_class_init_full (module_vtable, raise_exception);
331 method = mono_class_get_cctor (klass);
333 vtable->initialized = 1;
337 tid = mono_native_thread_id_get ();
339 mono_type_initialization_lock ();
340 /* double check... */
341 if (vtable->initialized) {
342 mono_type_initialization_unlock ();
345 if (vtable->init_failed) {
346 mono_type_initialization_unlock ();
348 /* The type initialization already failed once, rethrow the same exception */
350 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
351 return get_type_init_exception_for_vtable (vtable);
353 lock = (TypeInitializationLock *)g_hash_table_lookup (type_initialization_hash, vtable);
355 /* This thread will get to do the initialization */
356 if (mono_domain_get () != domain) {
357 /* Transfer into the target domain */
358 last_domain = mono_domain_get ();
359 if (!mono_domain_set (domain, FALSE)) {
360 vtable->initialized = 1;
361 mono_type_initialization_unlock ();
363 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
364 return mono_get_exception_appdomain_unloaded ();
367 lock = (TypeInitializationLock *)g_malloc (sizeof (TypeInitializationLock));
368 mono_coop_mutex_init_recursive (&lock->initialization_section);
369 lock->initializing_tid = tid;
370 lock->waiting_count = 1;
372 /* grab the vtable lock while this thread still owns type_initialization_section */
373 /* This is why type_initialization_lock needs to enter blocking mode */
374 mono_type_init_lock (lock);
375 g_hash_table_insert (type_initialization_hash, vtable, lock);
376 do_initialization = 1;
379 TypeInitializationLock *pending_lock;
381 if (mono_native_thread_id_equals (lock->initializing_tid, tid) || lock->done) {
382 mono_type_initialization_unlock ();
385 /* see if the thread doing the initialization is already blocked on this thread */
386 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (lock->initializing_tid));
387 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
388 if (mono_native_thread_id_equals (pending_lock->initializing_tid, tid)) {
389 if (!pending_lock->done) {
390 mono_type_initialization_unlock ();
393 /* the thread doing the initialization is blocked on this thread,
394 but on a lock that has already been freed. It just hasn't got
399 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (pending_lock->initializing_tid));
401 ++lock->waiting_count;
402 /* record the fact that we are waiting on the initializing thread */
403 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
405 mono_type_initialization_unlock ();
407 if (do_initialization) {
408 mono_runtime_try_invoke (method, NULL, NULL, (MonoObject**) &exc, &error);
409 if (exc == NULL && !mono_error_ok (&error))
410 exc = mono_error_convert_to_exception (&error);
412 mono_error_cleanup (&error);
414 /* If the initialization failed, mark the class as unusable. */
415 /* Avoid infinite loops */
417 (klass->image == mono_defaults.corlib &&
418 !strcmp (klass->name_space, "System") &&
419 !strcmp (klass->name, "TypeInitializationException")))) {
420 vtable->init_failed = 1;
422 if (klass->name_space && *klass->name_space)
423 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
425 full_name = g_strdup (klass->name);
426 exc_to_throw = mono_get_exception_type_initialization (full_name, exc);
430 * Store the exception object so it could be thrown on subsequent
433 mono_domain_lock (domain);
434 if (!domain->type_init_exception_hash)
435 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");
436 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
437 mono_domain_unlock (domain);
441 mono_domain_set (last_domain, TRUE);
443 mono_type_init_unlock (lock);
445 /* this just blocks until the initializing thread is done */
446 mono_type_init_lock (lock);
447 mono_type_init_unlock (lock);
450 mono_type_initialization_lock ();
451 if (!mono_native_thread_id_equals (lock->initializing_tid, tid))
452 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
453 --lock->waiting_count;
454 if (lock->waiting_count == 0) {
455 mono_coop_mutex_destroy (&lock->initialization_section);
456 g_hash_table_remove (type_initialization_hash, vtable);
459 mono_memory_barrier ();
460 if (!vtable->init_failed)
461 vtable->initialized = 1;
462 mono_type_initialization_unlock ();
464 if (vtable->init_failed) {
465 /* Either we were the initializing thread or we waited for the initialization */
467 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
468 return get_type_init_exception_for_vtable (vtable);
474 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
476 MONO_REQ_GC_NEUTRAL_MODE;
478 MonoVTable *vtable = (MonoVTable*)key;
480 TypeInitializationLock *lock = (TypeInitializationLock*) value;
481 if (mono_native_thread_id_equals (lock->initializing_tid, MONO_UINT_TO_NATIVE_THREAD_ID (GPOINTER_TO_UINT (user))) && !lock->done) {
484 * Have to set this since it cannot be set by the normal code in
485 * mono_runtime_class_init (). In this case, the exception object is not stored,
486 * and get_type_init_exception_for_class () needs to be aware of this.
488 vtable->init_failed = 1;
489 mono_type_init_unlock (lock);
490 --lock->waiting_count;
491 if (lock->waiting_count == 0) {
492 mono_coop_mutex_destroy (&lock->initialization_section);
501 mono_release_type_locks (MonoInternalThread *thread)
503 MONO_REQ_GC_UNSAFE_MODE;
505 mono_type_initialization_lock ();
506 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, GUINT_TO_POINTER (thread->tid));
507 mono_type_initialization_unlock ();
511 default_trampoline (MonoMethod *method)
517 default_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
519 g_assert_not_reached ();
524 #ifndef DISABLE_REMOTING
527 default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target)
529 g_error ("remoting not installed");
533 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
537 default_delegate_trampoline (MonoDomain *domain, MonoClass *klass)
539 g_assert_not_reached ();
543 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
544 static MonoImtThunkBuilder imt_thunk_builder;
545 static gboolean always_build_imt_thunks;
547 #if (MONO_IMT_SIZE > 32)
548 #error "MONO_IMT_SIZE cannot be larger than 32"
552 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
554 memcpy (&callbacks, cbs, sizeof (*cbs));
557 MonoRuntimeCallbacks*
558 mono_get_runtime_callbacks (void)
563 #ifndef DISABLE_REMOTING
565 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
567 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
572 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
574 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
578 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
579 imt_thunk_builder = func;
583 mono_set_always_build_imt_thunks (gboolean value)
585 always_build_imt_thunks = value;
589 * mono_compile_method:
590 * @method: The method to compile.
592 * This JIT-compiles the method, and returns the pointer to the native code
596 mono_compile_method (MonoMethod *method)
601 MONO_REQ_GC_NEUTRAL_MODE
603 if (!callbacks.compile_method) {
604 g_error ("compile method called on uninitialized runtime");
607 res = callbacks.compile_method (method, &error);
608 if (!mono_error_ok (&error))
609 mono_error_raise_exception (&error);
614 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
619 MONO_REQ_GC_NEUTRAL_MODE;
621 res = callbacks.create_jump_trampoline (domain, method, add_sync_wrapper, &error);
622 if (!mono_error_ok (&error))
623 mono_error_raise_exception (&error); /* FIXME: Don't raise here */
628 mono_runtime_create_delegate_trampoline (MonoClass *klass)
630 MONO_REQ_GC_NEUTRAL_MODE
632 return arch_create_delegate_trampoline (mono_domain_get (), klass);
635 static MonoFreeMethodFunc default_mono_free_method = NULL;
638 * mono_install_free_method:
639 * @func: pointer to the MonoFreeMethodFunc used to release a method
641 * This is an internal VM routine, it is used for the engines to
642 * register a handler to release the resources associated with a method.
644 * Methods are freed when no more references to the delegate that holds
648 mono_install_free_method (MonoFreeMethodFunc func)
650 default_mono_free_method = func;
654 * mono_runtime_free_method:
655 * @domain; domain where the method is hosted
656 * @method: method to release
658 * This routine is invoked to free the resources associated with
659 * a method that has been JIT compiled. This is used to discard
660 * methods that were used only temporarily (for example, used in marshalling)
664 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
666 MONO_REQ_GC_NEUTRAL_MODE
668 if (default_mono_free_method != NULL)
669 default_mono_free_method (domain, method);
671 mono_method_clear_object (domain, method);
673 mono_free_method (method);
677 * The vtables in the root appdomain are assumed to be reachable by other
678 * roots, and we don't use typed allocation in the other domains.
681 /* The sync block is no longer a GC pointer */
682 #define GC_HEADER_BITMAP (0)
684 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
687 compute_class_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
689 MONO_REQ_GC_NEUTRAL_MODE;
691 MonoClassField *field;
697 max_size = mono_class_data_size (klass) / sizeof (gpointer);
699 max_size = klass->instance_size / sizeof (gpointer);
700 if (max_size > size) {
701 g_assert (offset <= 0);
702 bitmap = (gsize *)g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
707 /*An Ephemeron cannot be marked by sgen*/
708 if (!static_fields && klass->image == mono_defaults.corlib && !strcmp ("Ephemeron", klass->name)) {
710 memset (bitmap, 0, size / 8);
715 for (p = klass; p != NULL; p = p->parent) {
716 gpointer iter = NULL;
717 while ((field = mono_class_get_fields (p, &iter))) {
721 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
723 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
726 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
729 /* FIXME: should not happen, flag as type load error */
730 if (field->type->byref)
733 if (static_fields && field->offset == -1)
737 pos = field->offset / sizeof (gpointer);
740 type = mono_type_get_underlying_type (field->type);
741 switch (type->type) {
744 case MONO_TYPE_FNPTR:
746 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
751 if (klass->image != mono_defaults.corlib)
754 case MONO_TYPE_STRING:
755 case MONO_TYPE_SZARRAY:
756 case MONO_TYPE_CLASS:
757 case MONO_TYPE_OBJECT:
758 case MONO_TYPE_ARRAY:
759 g_assert ((field->offset % sizeof(gpointer)) == 0);
761 g_assert (pos < size || pos <= max_size);
762 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
763 *max_set = MAX (*max_set, pos);
765 case MONO_TYPE_GENERICINST:
766 if (!mono_type_generic_inst_is_valuetype (type)) {
767 g_assert ((field->offset % sizeof(gpointer)) == 0);
769 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
770 *max_set = MAX (*max_set, pos);
775 case MONO_TYPE_VALUETYPE: {
776 MonoClass *fclass = mono_class_from_mono_type (field->type);
777 if (fclass->has_references) {
778 /* remove the object header */
779 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
793 case MONO_TYPE_BOOLEAN:
797 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
808 * mono_class_compute_bitmap:
810 * Mono internal function to compute a bitmap of reference fields in a class.
813 mono_class_compute_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
815 MONO_REQ_GC_NEUTRAL_MODE;
817 return compute_class_bitmap (klass, bitmap, size, offset, max_set, static_fields);
822 * similar to the above, but sets the bits in the bitmap for any non-ref field
823 * and ignores static fields
826 compute_class_non_ref_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset)
828 MonoClassField *field;
833 max_size = class->instance_size / sizeof (gpointer);
834 if (max_size >= size) {
835 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
838 for (p = class; p != NULL; p = p->parent) {
839 gpointer iter = NULL;
840 while ((field = mono_class_get_fields (p, &iter))) {
843 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
845 /* FIXME: should not happen, flag as type load error */
846 if (field->type->byref)
849 pos = field->offset / sizeof (gpointer);
852 type = mono_type_get_underlying_type (field->type);
853 switch (type->type) {
854 #if SIZEOF_VOID_P == 8
858 case MONO_TYPE_FNPTR:
863 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
864 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
865 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
868 #if SIZEOF_VOID_P == 4
872 case MONO_TYPE_FNPTR:
877 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
878 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
879 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
885 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
886 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
887 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
890 case MONO_TYPE_BOOLEAN:
893 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
895 case MONO_TYPE_STRING:
896 case MONO_TYPE_SZARRAY:
897 case MONO_TYPE_CLASS:
898 case MONO_TYPE_OBJECT:
899 case MONO_TYPE_ARRAY:
901 case MONO_TYPE_GENERICINST:
902 if (!mono_type_generic_inst_is_valuetype (type)) {
907 case MONO_TYPE_VALUETYPE: {
908 MonoClass *fclass = mono_class_from_mono_type (field->type);
909 /* remove the object header */
910 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
914 g_assert_not_reached ();
923 * mono_class_insecure_overlapping:
924 * check if a class with explicit layout has references and non-references
925 * fields overlapping.
927 * Returns: TRUE if it is insecure to load the type.
930 mono_class_insecure_overlapping (MonoClass *klass)
934 gsize default_bitmap [4] = {0};
936 gsize default_nrbitmap [4] = {0};
937 int i, insecure = FALSE;
940 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
941 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
943 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
944 int idx = i % (sizeof (bitmap [0]) * 8);
945 if (bitmap [idx] & nrbitmap [idx]) {
950 if (bitmap != default_bitmap)
952 if (nrbitmap != default_nrbitmap)
955 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
963 ves_icall_string_alloc (int length)
966 MonoString *str = mono_string_new_size_checked (mono_domain_get (), length, &error);
967 mono_error_raise_exception (&error);
973 mono_class_compute_gc_descriptor (MonoClass *klass)
975 MONO_REQ_GC_NEUTRAL_MODE;
979 gsize default_bitmap [4] = {0};
980 static gboolean gcj_inited = FALSE;
985 mono_register_jit_icall (ves_icall_object_new_fast, "ves_icall_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
986 mono_register_jit_icall (ves_icall_string_alloc, "ves_icall_string_alloc", mono_create_icall_signature ("object int"), FALSE);
989 mono_loader_unlock ();
993 mono_class_init (klass);
995 if (klass->gc_descr_inited)
998 klass->gc_descr_inited = TRUE;
999 klass->gc_descr = MONO_GC_DESCRIPTOR_NULL;
1001 bitmap = default_bitmap;
1002 if (klass == mono_defaults.string_class) {
1003 klass->gc_descr = mono_gc_make_descr_for_string (bitmap, 2);
1004 } else if (klass->rank) {
1005 mono_class_compute_gc_descriptor (klass->element_class);
1006 if (MONO_TYPE_IS_REFERENCE (&klass->element_class->byval_arg)) {
1008 klass->gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
1009 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1010 class->name_space, class->name);*/
1012 /* remove the object header */
1013 bitmap = compute_class_bitmap (klass->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
1014 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));
1015 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1016 class->name_space, class->name);*/
1017 if (bitmap != default_bitmap)
1021 /*static int count = 0;
1024 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1025 klass->gc_descr = mono_gc_make_descr_for_object (bitmap, max_set + 1, klass->instance_size);
1027 if (class->gc_descr == MONO_GC_DESCRIPTOR_NULL)
1028 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
1030 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
1031 if (bitmap != default_bitmap)
1037 * field_is_special_static:
1038 * @fklass: The MonoClass to look up.
1039 * @field: The MonoClassField describing the field.
1041 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1042 * SPECIAL_STATIC_NONE otherwise.
1045 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1047 MONO_REQ_GC_NEUTRAL_MODE;
1049 MonoCustomAttrInfo *ainfo;
1051 ainfo = mono_custom_attrs_from_field (fklass, field);
1054 for (i = 0; i < ainfo->num_attrs; ++i) {
1055 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1056 if (klass->image == mono_defaults.corlib) {
1057 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1058 mono_custom_attrs_free (ainfo);
1059 return SPECIAL_STATIC_THREAD;
1061 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1062 mono_custom_attrs_free (ainfo);
1063 return SPECIAL_STATIC_CONTEXT;
1067 mono_custom_attrs_free (ainfo);
1068 return SPECIAL_STATIC_NONE;
1071 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1072 #define mix(a,b,c) { \
1073 a -= c; a ^= rot(c, 4); c += b; \
1074 b -= a; b ^= rot(a, 6); a += c; \
1075 c -= b; c ^= rot(b, 8); b += a; \
1076 a -= c; a ^= rot(c,16); c += b; \
1077 b -= a; b ^= rot(a,19); a += c; \
1078 c -= b; c ^= rot(b, 4); b += a; \
1080 #define final(a,b,c) { \
1081 c ^= b; c -= rot(b,14); \
1082 a ^= c; a -= rot(c,11); \
1083 b ^= a; b -= rot(a,25); \
1084 c ^= b; c -= rot(b,16); \
1085 a ^= c; a -= rot(c,4); \
1086 b ^= a; b -= rot(a,14); \
1087 c ^= b; c -= rot(b,24); \
1091 * mono_method_get_imt_slot:
1093 * The IMT slot is embedded into AOTed code, so this must return the same value
1094 * for the same method across all executions. This means:
1095 * - pointers shouldn't be used as hash values.
1096 * - mono_metadata_str_hash () should be used for hashing strings.
1099 mono_method_get_imt_slot (MonoMethod *method)
1101 MONO_REQ_GC_NEUTRAL_MODE;
1103 MonoMethodSignature *sig;
1105 guint32 *hashes_start, *hashes;
1109 /* This can be used to stress tests the collision code */
1113 * We do this to simplify generic sharing. It will hurt
1114 * performance in cases where a class implements two different
1115 * instantiations of the same generic interface.
1116 * The code in build_imt_slots () depends on this.
1118 if (method->is_inflated)
1119 method = ((MonoMethodInflated*)method)->declaring;
1121 sig = mono_method_signature (method);
1122 hashes_count = sig->param_count + 4;
1123 hashes_start = (guint32 *)malloc (hashes_count * sizeof (guint32));
1124 hashes = hashes_start;
1126 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1127 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1128 method->klass->name_space, method->klass->name, method->name);
1131 /* Initialize hashes */
1132 hashes [0] = mono_metadata_str_hash (method->klass->name);
1133 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1134 hashes [2] = mono_metadata_str_hash (method->name);
1135 hashes [3] = mono_metadata_type_hash (sig->ret);
1136 for (i = 0; i < sig->param_count; i++) {
1137 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1140 /* Setup internal state */
1141 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1143 /* Handle most of the hashes */
1144 while (hashes_count > 3) {
1153 /* Handle the last 3 hashes (all the case statements fall through) */
1154 switch (hashes_count) {
1155 case 3 : c += hashes [2];
1156 case 2 : b += hashes [1];
1157 case 1 : a += hashes [0];
1159 case 0: /* nothing left to add */
1163 free (hashes_start);
1164 /* Report the result */
1165 return c % MONO_IMT_SIZE;
1174 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1175 MONO_REQ_GC_NEUTRAL_MODE;
1177 guint32 imt_slot = mono_method_get_imt_slot (method);
1178 MonoImtBuilderEntry *entry;
1180 if (slot_num >= 0 && imt_slot != slot_num) {
1181 /* we build just a single imt slot and this is not it */
1185 entry = (MonoImtBuilderEntry *)g_malloc0 (sizeof (MonoImtBuilderEntry));
1186 entry->key = method;
1187 entry->value.vtable_slot = vtable_slot;
1188 entry->next = imt_builder [imt_slot];
1189 if (imt_builder [imt_slot] != NULL) {
1190 entry->children = imt_builder [imt_slot]->children + 1;
1191 if (entry->children == 1) {
1192 mono_stats.imt_slots_with_collisions++;
1193 *imt_collisions_bitmap |= (1 << imt_slot);
1196 entry->children = 0;
1197 mono_stats.imt_used_slots++;
1199 imt_builder [imt_slot] = entry;
1202 char *method_name = mono_method_full_name (method, TRUE);
1203 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1204 method, method_name, imt_slot, vtable_slot, entry->children);
1205 g_free (method_name);
1212 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1214 MonoMethod *method = e->key;
1215 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1219 method->klass->name_space,
1220 method->klass->name,
1223 printf (" * %s: NULL\n", message);
1229 compare_imt_builder_entries (const void *p1, const void *p2) {
1230 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1231 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1233 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1237 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1239 MONO_REQ_GC_NEUTRAL_MODE;
1241 int count = end - start;
1242 int chunk_start = out_array->len;
1245 for (i = start; i < end; ++i) {
1246 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1247 item->key = sorted_array [i]->key;
1248 item->value = sorted_array [i]->value;
1249 item->has_target_code = sorted_array [i]->has_target_code;
1250 item->is_equals = TRUE;
1252 item->check_target_idx = out_array->len + 1;
1254 item->check_target_idx = 0;
1255 g_ptr_array_add (out_array, item);
1258 int middle = start + count / 2;
1259 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1261 item->key = sorted_array [middle]->key;
1262 item->is_equals = FALSE;
1263 g_ptr_array_add (out_array, item);
1264 imt_emit_ir (sorted_array, start, middle, out_array);
1265 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1271 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1272 MONO_REQ_GC_NEUTRAL_MODE;
1274 int number_of_entries = entries->children + 1;
1275 MonoImtBuilderEntry **sorted_array = (MonoImtBuilderEntry **)malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1276 GPtrArray *result = g_ptr_array_new ();
1277 MonoImtBuilderEntry *current_entry;
1280 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1281 sorted_array [i] = current_entry;
1283 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1285 /*for (i = 0; i < number_of_entries; i++) {
1286 print_imt_entry (" sorted array:", sorted_array [i], i);
1289 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1291 free (sorted_array);
1296 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1298 MONO_REQ_GC_NEUTRAL_MODE;
1300 if (imt_builder_entry != NULL) {
1301 if (imt_builder_entry->children == 0 && !fail_tramp && !always_build_imt_thunks) {
1302 /* No collision, return the vtable slot contents */
1303 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1305 /* Collision, build the thunk */
1306 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1309 result = imt_thunk_builder (vtable, domain,
1310 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1311 for (i = 0; i < imt_ir->len; ++i)
1312 g_free (g_ptr_array_index (imt_ir, i));
1313 g_ptr_array_free (imt_ir, TRUE);
1325 static MonoImtBuilderEntry*
1326 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1329 * LOCKING: requires the loader and domain locks.
1333 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1335 MONO_REQ_GC_NEUTRAL_MODE;
1339 guint32 imt_collisions_bitmap = 0;
1340 MonoImtBuilderEntry **imt_builder = (MonoImtBuilderEntry **)calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1341 int method_count = 0;
1342 gboolean record_method_count_for_max_collisions = FALSE;
1343 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1346 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1348 for (i = 0; i < klass->interface_offsets_count; ++i) {
1349 MonoClass *iface = klass->interfaces_packed [i];
1350 int interface_offset = klass->interface_offsets_packed [i];
1351 int method_slot_in_interface, vt_slot;
1353 if (mono_class_has_variant_generic_params (iface))
1354 has_variant_iface = TRUE;
1356 mono_class_setup_methods (iface);
1357 vt_slot = interface_offset;
1358 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1361 if (slot_num >= 0 && iface->is_inflated) {
1363 * The imt slot of the method is the same as for its declaring method,
1364 * see the comment in mono_method_get_imt_slot (), so we can
1365 * avoid inflating methods which will be discarded by
1366 * add_imt_builder_entry anyway.
1368 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1369 if (mono_method_get_imt_slot (method) != slot_num) {
1374 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1375 if (method->is_generic) {
1376 has_generic_virtual = TRUE;
1381 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1382 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1387 if (extra_interfaces) {
1388 int interface_offset = klass->vtable_size;
1390 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1391 MonoClass* iface = (MonoClass *)list_item->data;
1392 int method_slot_in_interface;
1393 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1394 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1396 if (method->is_generic)
1397 has_generic_virtual = TRUE;
1398 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1400 interface_offset += iface->method.count;
1403 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1404 /* overwrite the imt slot only if we're building all the entries or if
1405 * we're building this specific one
1407 if (slot_num < 0 || i == slot_num) {
1408 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1411 if (imt_builder [i]) {
1412 MonoImtBuilderEntry *entry;
1414 /* Link entries with imt_builder [i] */
1415 for (entry = entries; entry->next; entry = entry->next) {
1417 MonoMethod *method = (MonoMethod*)entry->key;
1418 char *method_name = mono_method_full_name (method, TRUE);
1419 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1420 g_free (method_name);
1423 entry->next = imt_builder [i];
1424 entries->children += imt_builder [i]->children + 1;
1426 imt_builder [i] = entries;
1429 if (has_generic_virtual || has_variant_iface) {
1431 * There might be collisions later when the the thunk is expanded.
1433 imt_collisions_bitmap |= (1 << i);
1436 * The IMT thunk might be called with an instance of one of the
1437 * generic virtual methods, so has to fallback to the IMT trampoline.
1439 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline (vt, i));
1441 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1444 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1448 if (imt_builder [i] != NULL) {
1449 int methods_in_slot = imt_builder [i]->children + 1;
1450 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1451 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1452 record_method_count_for_max_collisions = TRUE;
1454 method_count += methods_in_slot;
1458 mono_stats.imt_number_of_methods += method_count;
1459 if (record_method_count_for_max_collisions) {
1460 mono_stats.imt_method_count_when_max_collisions = method_count;
1463 for (i = 0; i < MONO_IMT_SIZE; i++) {
1464 MonoImtBuilderEntry* entry = imt_builder [i];
1465 while (entry != NULL) {
1466 MonoImtBuilderEntry* next = entry->next;
1472 /* we OR the bitmap since we may build just a single imt slot at a time */
1473 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1477 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1478 MONO_REQ_GC_NEUTRAL_MODE;
1480 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1484 * mono_vtable_build_imt_slot:
1485 * @vtable: virtual object table struct
1486 * @imt_slot: slot in the IMT table
1488 * Fill the given @imt_slot in the IMT table of @vtable with
1489 * a trampoline or a thunk for the case of collisions.
1490 * This is part of the internal mono API.
1492 * LOCKING: Take the domain lock.
1495 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1497 MONO_REQ_GC_NEUTRAL_MODE;
1499 gpointer *imt = (gpointer*)vtable;
1500 imt -= MONO_IMT_SIZE;
1501 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1503 /* no support for extra interfaces: the proxy objects will need
1504 * to build the complete IMT
1505 * Update and heck needs to ahppen inside the proper domain lock, as all
1506 * the changes made to a MonoVTable.
1508 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1509 mono_domain_lock (vtable->domain);
1510 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1511 if (!callbacks.imt_entry_inited (vtable, imt_slot))
1512 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1513 mono_domain_unlock (vtable->domain);
1514 mono_loader_unlock ();
1519 * The first two free list entries both belong to the wait list: The
1520 * first entry is the pointer to the head of the list and the second
1521 * entry points to the last element. That way appending and removing
1522 * the first element are both O(1) operations.
1524 #ifdef MONO_SMALL_CONFIG
1525 #define NUM_FREE_LISTS 6
1527 #define NUM_FREE_LISTS 12
1529 #define FIRST_FREE_LIST_SIZE 64
1530 #define MAX_WAIT_LENGTH 50
1531 #define THUNK_THRESHOLD 10
1534 * LOCKING: The domain lock must be held.
1537 init_thunk_free_lists (MonoDomain *domain)
1539 MONO_REQ_GC_NEUTRAL_MODE;
1541 if (domain->thunk_free_lists)
1543 domain->thunk_free_lists = (MonoThunkFreeList **)mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1547 list_index_for_size (int item_size)
1550 int size = FIRST_FREE_LIST_SIZE;
1552 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1561 * mono_method_alloc_generic_virtual_thunk:
1563 * @size: size in bytes
1565 * Allocs size bytes to be used for the code of a generic virtual
1566 * thunk. It's either allocated from the domain's code manager or
1567 * reused from a previously invalidated piece.
1569 * LOCKING: The domain lock must be held.
1572 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1574 MONO_REQ_GC_NEUTRAL_MODE;
1576 static gboolean inited = FALSE;
1577 static int generic_virtual_thunks_size = 0;
1581 MonoThunkFreeList **l;
1583 init_thunk_free_lists (domain);
1585 size += sizeof (guint32);
1586 if (size < sizeof (MonoThunkFreeList))
1587 size = sizeof (MonoThunkFreeList);
1589 i = list_index_for_size (size);
1590 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1591 if ((*l)->size >= size) {
1592 MonoThunkFreeList *item = *l;
1594 return ((guint32*)item) + 1;
1598 /* no suitable item found - search lists of larger sizes */
1599 while (++i < NUM_FREE_LISTS) {
1600 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1603 g_assert (item->size > size);
1604 domain->thunk_free_lists [i] = item->next;
1605 return ((guint32*)item) + 1;
1608 /* still nothing found - allocate it */
1610 mono_counters_register ("Generic virtual thunk bytes",
1611 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1614 generic_virtual_thunks_size += size;
1616 p = (guint32 *)mono_domain_code_reserve (domain, size);
1619 mono_domain_lock (domain);
1620 if (!domain->generic_virtual_thunks)
1621 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1622 g_hash_table_insert (domain->generic_virtual_thunks, p, p);
1623 mono_domain_unlock (domain);
1629 * LOCKING: The domain lock must be held.
1632 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1634 MONO_REQ_GC_NEUTRAL_MODE;
1636 guint32 *p = (guint32 *)code;
1637 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1638 gboolean found = FALSE;
1640 mono_domain_lock (domain);
1641 if (!domain->generic_virtual_thunks)
1642 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1643 if (g_hash_table_lookup (domain->generic_virtual_thunks, l))
1645 mono_domain_unlock (domain);
1648 /* Not allocated by mono_method_alloc_generic_virtual_thunk (), i.e. AOT */
1650 init_thunk_free_lists (domain);
1652 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1653 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1654 int length = item->length;
1657 /* unlink the first item from the wait list */
1658 domain->thunk_free_lists [0] = item->next;
1659 domain->thunk_free_lists [0]->length = length - 1;
1661 i = list_index_for_size (item->size);
1663 /* put it in the free list */
1664 item->next = domain->thunk_free_lists [i];
1665 domain->thunk_free_lists [i] = item;
1669 if (domain->thunk_free_lists [1]) {
1670 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1671 domain->thunk_free_lists [0]->length++;
1673 g_assert (!domain->thunk_free_lists [0]);
1675 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1676 domain->thunk_free_lists [0]->length = 1;
1680 typedef struct _GenericVirtualCase {
1684 struct _GenericVirtualCase *next;
1685 } GenericVirtualCase;
1688 * get_generic_virtual_entries:
1690 * Return IMT entries for the generic virtual method instances and
1691 * variant interface methods for vtable slot
1694 static MonoImtBuilderEntry*
1695 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1697 MONO_REQ_GC_NEUTRAL_MODE;
1699 GenericVirtualCase *list;
1700 MonoImtBuilderEntry *entries;
1702 mono_domain_lock (domain);
1703 if (!domain->generic_virtual_cases)
1704 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1706 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1709 for (; list; list = list->next) {
1710 MonoImtBuilderEntry *entry;
1712 if (list->count < THUNK_THRESHOLD)
1715 entry = g_new0 (MonoImtBuilderEntry, 1);
1716 entry->key = list->method;
1717 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1718 entry->has_target_code = 1;
1720 entry->children = entries->children + 1;
1721 entry->next = entries;
1725 mono_domain_unlock (domain);
1727 /* FIXME: Leaking memory ? */
1732 * mono_method_add_generic_virtual_invocation:
1734 * @vtable_slot: pointer to the vtable slot
1735 * @method: the inflated generic virtual method
1736 * @code: the method's code
1738 * Registers a call via unmanaged code to a generic virtual method
1739 * instantiation or variant interface method. If the number of calls reaches a threshold
1740 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1741 * virtual method thunk.
1744 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1745 gpointer *vtable_slot,
1746 MonoMethod *method, gpointer code)
1748 MONO_REQ_GC_NEUTRAL_MODE;
1750 static gboolean inited = FALSE;
1751 static int num_added = 0;
1753 GenericVirtualCase *gvc, *list;
1754 MonoImtBuilderEntry *entries;
1758 mono_domain_lock (domain);
1759 if (!domain->generic_virtual_cases)
1760 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1762 /* Check whether the case was already added */
1763 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1766 if (gvc->method == method)
1771 /* If not found, make a new one */
1773 gvc = (GenericVirtualCase *)mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1774 gvc->method = method;
1777 gvc->next = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1779 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1782 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1788 if (++gvc->count == THUNK_THRESHOLD) {
1789 gpointer *old_thunk = (void **)*vtable_slot;
1790 gpointer vtable_trampoline = NULL;
1791 gpointer imt_trampoline = NULL;
1793 if ((gpointer)vtable_slot < (gpointer)vtable) {
1794 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1795 int imt_slot = MONO_IMT_SIZE + displacement;
1797 /* Force the rebuild of the thunk at the next call */
1798 imt_trampoline = callbacks.get_imt_trampoline (vtable, imt_slot);
1799 *vtable_slot = imt_trampoline;
1801 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline (vtable, (gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1803 entries = get_generic_virtual_entries (domain, vtable_slot);
1805 sorted = imt_sort_slot_entries (entries);
1807 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1811 MonoImtBuilderEntry *next = entries->next;
1816 for (i = 0; i < sorted->len; ++i)
1817 g_free (g_ptr_array_index (sorted, i));
1818 g_ptr_array_free (sorted, TRUE);
1821 #ifndef __native_client__
1822 /* We don't re-use any thunks as there is a lot of overhead */
1823 /* to deleting and re-using code in Native Client. */
1824 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1825 invalidate_generic_virtual_thunk (domain, old_thunk);
1829 mono_domain_unlock (domain);
1832 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, gboolean raise_on_error);
1835 * mono_class_vtable:
1836 * @domain: the application domain
1837 * @class: the class to initialize
1839 * VTables are domain specific because we create domain specific code, and
1840 * they contain the domain specific static class data.
1841 * On failure, NULL is returned, and class->exception_type is set.
1844 mono_class_vtable (MonoDomain *domain, MonoClass *klass)
1846 return mono_class_vtable_full (domain, klass, FALSE);
1850 * mono_class_vtable_full:
1851 * @domain: the application domain
1852 * @class: the class to initialize
1853 * @raise_on_error if an exception should be raised on failure or not
1855 * VTables are domain specific because we create domain specific code, and
1856 * they contain the domain specific static class data.
1859 mono_class_vtable_full (MonoDomain *domain, MonoClass *klass, gboolean raise_on_error)
1861 MONO_REQ_GC_UNSAFE_MODE;
1863 MonoClassRuntimeInfo *runtime_info;
1867 if (mono_class_has_failure (klass)) {
1869 mono_raise_exception (mono_class_get_exception_for_failure (klass));
1873 /* this check can be inlined in jitted code, too */
1874 runtime_info = klass->runtime_info;
1875 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1876 return runtime_info->domain_vtables [domain->domain_id];
1877 return mono_class_create_runtime_vtable (domain, klass, raise_on_error);
1881 * mono_class_try_get_vtable:
1882 * @domain: the application domain
1883 * @class: the class to initialize
1885 * This function tries to get the associated vtable from @class if
1886 * it was already created.
1889 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *klass)
1891 MONO_REQ_GC_NEUTRAL_MODE;
1893 MonoClassRuntimeInfo *runtime_info;
1897 runtime_info = klass->runtime_info;
1898 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1899 return runtime_info->domain_vtables [domain->domain_id];
1904 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1906 MONO_REQ_GC_NEUTRAL_MODE;
1908 size_t alloc_offset;
1911 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1912 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1913 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1915 if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1916 g_assert ((imt_table_bytes & 7) == 4);
1923 return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1927 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, gboolean raise_on_error)
1929 MONO_REQ_GC_UNSAFE_MODE;
1933 MonoClassRuntimeInfo *runtime_info, *old_info;
1934 MonoClassField *field;
1936 int i, vtable_slots;
1937 size_t imt_table_bytes;
1939 guint32 vtable_size, class_size;
1941 gpointer *interface_offsets;
1943 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1944 mono_domain_lock (domain);
1945 runtime_info = klass->runtime_info;
1946 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1947 mono_domain_unlock (domain);
1948 mono_loader_unlock ();
1949 return runtime_info->domain_vtables [domain->domain_id];
1951 if (!klass->inited || mono_class_has_failure (klass)) {
1952 if (!mono_class_init (klass) || mono_class_has_failure (klass)) {
1953 mono_domain_unlock (domain);
1954 mono_loader_unlock ();
1956 mono_raise_exception (mono_class_get_exception_for_failure (klass));
1961 /* Array types require that their element type be valid*/
1962 if (klass->byval_arg.type == MONO_TYPE_ARRAY || klass->byval_arg.type == MONO_TYPE_SZARRAY) {
1963 MonoClass *element_class = klass->element_class;
1964 if (!element_class->inited)
1965 mono_class_init (element_class);
1967 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1968 if (!mono_class_has_failure (element_class) && !element_class->vtable_size)
1969 mono_class_setup_vtable (element_class);
1971 if (mono_class_has_failure (element_class)) {
1972 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1973 if (!mono_class_has_failure (klass))
1974 mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
1975 mono_domain_unlock (domain);
1976 mono_loader_unlock ();
1978 mono_raise_exception (mono_class_get_exception_for_failure (klass));
1984 * For some classes, mono_class_init () already computed klass->vtable_size, and
1985 * that is all that is needed because of the vtable trampolines.
1987 if (!klass->vtable_size)
1988 mono_class_setup_vtable (klass);
1990 if (klass->generic_class && !klass->vtable)
1991 mono_class_check_vtable_constraints (klass, NULL);
1993 /* Initialize klass->has_finalize */
1994 mono_class_has_finalizer (klass);
1996 if (mono_class_has_failure (klass)) {
1997 mono_domain_unlock (domain);
1998 mono_loader_unlock ();
2000 mono_raise_exception (mono_class_get_exception_for_failure (klass));
2004 vtable_slots = klass->vtable_size;
2005 /* we add an additional vtable slot to store the pointer to static field data only when needed */
2006 class_size = mono_class_data_size (klass);
2010 if (klass->interface_offsets_count) {
2011 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
2012 mono_stats.imt_number_of_tables++;
2013 mono_stats.imt_tables_size += imt_table_bytes;
2015 imt_table_bytes = 0;
2018 vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
2020 mono_stats.used_class_count++;
2021 mono_stats.class_vtable_size += vtable_size;
2023 interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
2024 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2025 g_assert (!((gsize)vt & 7));
2028 vt->rank = klass->rank;
2029 vt->domain = domain;
2031 mono_class_compute_gc_descriptor (klass);
2033 * We can't use typed allocation in the non-root domains, since the
2034 * collector needs the GC descriptor stored in the vtable even after
2035 * the mempool containing the vtable is destroyed when the domain is
2036 * unloaded. An alternative might be to allocate vtables in the GC
2037 * heap, but this does not seem to work (it leads to crashes inside
2038 * libgc). If that approach is tried, two gc descriptors need to be
2039 * allocated for each class: one for the root domain, and one for all
2040 * other domains. The second descriptor should contain a bit for the
2041 * vtable field in MonoObject, since we can no longer assume the
2042 * vtable is reachable by other roots after the appdomain is unloaded.
2044 #ifdef HAVE_BOEHM_GC
2045 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
2046 vt->gc_descr = MONO_GC_DESCRIPTOR_NULL;
2049 vt->gc_descr = klass->gc_descr;
2051 gc_bits = mono_gc_get_vtable_bits (klass);
2052 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
2054 vt->gc_bits = gc_bits;
2057 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
2058 if (klass->has_static_refs) {
2059 MonoGCDescriptor statics_gc_descr;
2061 gsize default_bitmap [4] = {0};
2064 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
2065 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], klass->name_space, klass->name, class_size);*/
2066 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
2067 vt->vtable [klass->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr, MONO_ROOT_SOURCE_STATIC, "managed static variables");
2068 mono_domain_add_class_static_data (domain, klass, vt->vtable [klass->vtable_size], NULL);
2069 if (bitmap != default_bitmap)
2072 vt->vtable [klass->vtable_size] = mono_domain_alloc0 (domain, class_size);
2074 vt->has_static_fields = TRUE;
2075 mono_stats.class_static_data_size += class_size;
2079 while ((field = mono_class_get_fields (klass, &iter))) {
2080 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2082 if (mono_field_is_deleted (field))
2084 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2085 gint32 special_static = klass->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (klass, field);
2086 if (special_static != SPECIAL_STATIC_NONE) {
2087 guint32 size, offset;
2089 gsize default_bitmap [4] = {0};
2094 if (mono_type_is_reference (field->type)) {
2095 default_bitmap [0] = 1;
2097 bitmap = default_bitmap;
2098 } else if (mono_type_is_struct (field->type)) {
2099 fclass = mono_class_from_mono_type (field->type);
2100 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
2101 numbits = max_set + 1;
2103 default_bitmap [0] = 0;
2105 bitmap = default_bitmap;
2107 size = mono_type_size (field->type, &align);
2108 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
2109 if (!domain->special_static_fields)
2110 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2111 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2112 if (bitmap != default_bitmap)
2115 * This marks the field as special static to speed up the
2116 * checks in mono_field_static_get/set_value ().
2122 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2123 MonoClass *fklass = mono_class_from_mono_type (field->type);
2124 const char *data = mono_field_get_data (field);
2126 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2127 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2128 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2131 if (fklass->valuetype) {
2132 memcpy (t, data, mono_class_value_size (fklass, NULL));
2134 /* it's a pointer type: add check */
2135 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2142 vt->max_interface_id = klass->max_interface_id;
2143 vt->interface_bitmap = klass->interface_bitmap;
2145 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2146 // class->name, klass->interface_offsets_count);
2148 /* Initialize vtable */
2149 if (callbacks.get_vtable_trampoline) {
2150 // This also covers the AOT case
2151 for (i = 0; i < klass->vtable_size; ++i) {
2152 vt->vtable [i] = callbacks.get_vtable_trampoline (vt, i);
2155 mono_class_setup_vtable (klass);
2157 for (i = 0; i < klass->vtable_size; ++i) {
2160 cm = klass->vtable [i];
2162 vt->vtable [i] = callbacks.create_jit_trampoline (domain, cm, &error);
2163 if (!mono_error_ok (&error))
2164 mono_error_raise_exception (&error); /* FIXME: Don't raise here */
2169 if (imt_table_bytes) {
2170 /* Now that the vtable is full, we can actually fill up the IMT */
2171 for (i = 0; i < MONO_IMT_SIZE; ++i)
2172 interface_offsets [i] = callbacks.get_imt_trampoline (vt, i);
2176 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2177 * re-acquire them and check if another thread has created the vtable in the meantime.
2179 /* Special case System.MonoType to avoid infinite recursion */
2180 if (klass != mono_defaults.monotype_class) {
2181 /*FIXME check for OOM*/
2182 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, &error);
2183 mono_error_raise_exception (&error); /* FIXME don't raise here */
2185 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.monotype_class)
2186 /* This is unregistered in
2187 unregister_vtable_reflection_type() in
2189 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2192 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (klass));
2194 /* class_vtable_array keeps an array of created vtables
2196 g_ptr_array_add (domain->class_vtable_array, vt);
2197 /* klass->runtime_info is protected by the loader lock, both when
2198 * it it enlarged and when it is stored info.
2202 * Store the vtable in klass->runtime_info.
2203 * klass->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2205 mono_memory_barrier ();
2207 old_info = klass->runtime_info;
2208 if (old_info && old_info->max_domain >= domain->domain_id) {
2209 /* someone already created a large enough runtime info */
2210 old_info->domain_vtables [domain->domain_id] = vt;
2212 int new_size = domain->domain_id;
2214 new_size = MAX (new_size, old_info->max_domain);
2216 /* make the new size a power of two */
2218 while (new_size > i)
2221 /* this is a bounded memory retention issue: may want to
2222 * handle it differently when we'll have a rcu-like system.
2224 runtime_info = (MonoClassRuntimeInfo *)mono_image_alloc0 (klass->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2225 runtime_info->max_domain = new_size - 1;
2226 /* copy the stuff from the older info */
2228 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2230 runtime_info->domain_vtables [domain->domain_id] = vt;
2232 mono_memory_barrier ();
2233 klass->runtime_info = runtime_info;
2236 if (klass == mono_defaults.monotype_class) {
2237 /*FIXME check for OOM*/
2238 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, &error);
2239 mono_error_raise_exception (&error); /* FIXME don't raise here */
2241 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.monotype_class)
2242 /* This is unregistered in
2243 unregister_vtable_reflection_type() in
2245 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2248 mono_domain_unlock (domain);
2249 mono_loader_unlock ();
2251 /* make sure the parent is initialized */
2252 /*FIXME shouldn't this fail the current type?*/
2254 mono_class_vtable_full (domain, klass->parent, raise_on_error);
2259 #ifndef DISABLE_REMOTING
2261 * mono_class_proxy_vtable:
2262 * @domain: the application domain
2263 * @remove_class: the remote class
2265 * Creates a vtable for transparent proxies. It is basically
2266 * a copy of the real vtable of the class wrapped in @remote_class,
2267 * but all function pointers invoke the remoting functions, and
2268 * vtable->klass points to the transparent proxy class, and not to @class.
2271 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2273 MONO_REQ_GC_UNSAFE_MODE;
2276 MonoVTable *vt, *pvt;
2277 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2279 GSList *extra_interfaces = NULL;
2280 MonoClass *klass = remote_class->proxy_class;
2281 gpointer *interface_offsets;
2284 size_t imt_table_bytes;
2286 #ifdef COMPRESSED_INTERFACE_BITMAP
2290 vt = mono_class_vtable (domain, klass);
2291 g_assert (vt); /*FIXME property handle failure*/
2292 max_interface_id = vt->max_interface_id;
2294 /* Calculate vtable space for extra interfaces */
2295 for (j = 0; j < remote_class->interface_count; j++) {
2296 MonoClass* iclass = remote_class->interfaces[j];
2300 /*FIXME test for interfaces with variant generic arguments*/
2301 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, iclass->interface_id))
2302 continue; /* interface implemented by the class */
2303 if (g_slist_find (extra_interfaces, iclass))
2306 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2308 method_count = mono_class_num_methods (iclass);
2310 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2311 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2313 for (i = 0; i < ifaces->len; ++i) {
2314 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2315 /*FIXME test for interfaces with variant generic arguments*/
2316 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, ic->interface_id))
2317 continue; /* interface implemented by the class */
2318 if (g_slist_find (extra_interfaces, ic))
2320 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2321 method_count += mono_class_num_methods (ic);
2323 g_ptr_array_free (ifaces, TRUE);
2326 extra_interface_vtsize += method_count * sizeof (gpointer);
2327 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2330 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2331 mono_stats.imt_number_of_tables++;
2332 mono_stats.imt_tables_size += imt_table_bytes;
2334 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer);
2336 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2338 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2339 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2340 g_assert (!((gsize)pvt & 7));
2342 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer));
2344 pvt->klass = mono_defaults.transparent_proxy_class;
2345 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2346 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2348 /* initialize vtable */
2349 mono_class_setup_vtable (klass);
2350 for (i = 0; i < klass->vtable_size; ++i) {
2353 if ((cm = klass->vtable [i]))
2354 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2356 pvt->vtable [i] = NULL;
2359 if (klass->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2360 /* create trampolines for abstract methods */
2361 for (k = klass; k; k = k->parent) {
2363 gpointer iter = NULL;
2364 while ((m = mono_class_get_methods (k, &iter)))
2365 if (!pvt->vtable [m->slot])
2366 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2370 pvt->max_interface_id = max_interface_id;
2371 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2372 #ifdef COMPRESSED_INTERFACE_BITMAP
2373 bitmap = (uint8_t *)g_malloc0 (bsize);
2375 bitmap = (uint8_t *)mono_domain_alloc0 (domain, bsize);
2378 for (i = 0; i < klass->interface_offsets_count; ++i) {
2379 int interface_id = klass->interfaces_packed [i]->interface_id;
2380 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2383 if (extra_interfaces) {
2384 int slot = klass->vtable_size;
2390 /* Create trampolines for the methods of the interfaces */
2391 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2392 interf = (MonoClass *)list_item->data;
2394 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2398 while ((cm = mono_class_get_methods (interf, &iter)))
2399 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2401 slot += mono_class_num_methods (interf);
2405 /* Now that the vtable is full, we can actually fill up the IMT */
2406 build_imt (klass, pvt, domain, interface_offsets, extra_interfaces);
2407 if (extra_interfaces) {
2408 g_slist_free (extra_interfaces);
2411 #ifdef COMPRESSED_INTERFACE_BITMAP
2412 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2413 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2414 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2417 pvt->interface_bitmap = bitmap;
2422 #endif /* DISABLE_REMOTING */
2425 * mono_class_field_is_special_static:
2427 * Returns whether @field is a thread/context static field.
2430 mono_class_field_is_special_static (MonoClassField *field)
2432 MONO_REQ_GC_NEUTRAL_MODE
2434 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2436 if (mono_field_is_deleted (field))
2438 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2439 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2446 * mono_class_field_get_special_static_type:
2447 * @field: The MonoClassField describing the field.
2449 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2450 * SPECIAL_STATIC_NONE otherwise.
2453 mono_class_field_get_special_static_type (MonoClassField *field)
2455 MONO_REQ_GC_NEUTRAL_MODE
2457 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2458 return SPECIAL_STATIC_NONE;
2459 if (mono_field_is_deleted (field))
2460 return SPECIAL_STATIC_NONE;
2461 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2462 return field_is_special_static (field->parent, field);
2463 return SPECIAL_STATIC_NONE;
2467 * mono_class_has_special_static_fields:
2469 * Returns whenever @klass has any thread/context static fields.
2472 mono_class_has_special_static_fields (MonoClass *klass)
2474 MONO_REQ_GC_NEUTRAL_MODE
2476 MonoClassField *field;
2480 while ((field = mono_class_get_fields (klass, &iter))) {
2481 g_assert (field->parent == klass);
2482 if (mono_class_field_is_special_static (field))
2489 #ifndef DISABLE_REMOTING
2491 * create_remote_class_key:
2492 * Creates an array of pointers that can be used as a hash key for a remote class.
2493 * The first element of the array is the number of pointers.
2496 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2498 MONO_REQ_GC_NEUTRAL_MODE;
2503 if (remote_class == NULL) {
2504 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2505 key = (void **)g_malloc (sizeof(gpointer) * 3);
2506 key [0] = GINT_TO_POINTER (2);
2507 key [1] = mono_defaults.marshalbyrefobject_class;
2508 key [2] = extra_class;
2510 key = (void **)g_malloc (sizeof(gpointer) * 2);
2511 key [0] = GINT_TO_POINTER (1);
2512 key [1] = extra_class;
2515 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2516 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2517 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2518 key [1] = remote_class->proxy_class;
2520 // Keep the list of interfaces sorted
2521 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2522 if (extra_class && remote_class->interfaces [i] > extra_class) {
2523 key [j++] = extra_class;
2526 key [j] = remote_class->interfaces [i];
2529 key [j] = extra_class;
2531 // Replace the old class. The interface list is the same
2532 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2533 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2534 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2535 for (i = 0; i < remote_class->interface_count; i++)
2536 key [2 + i] = remote_class->interfaces [i];
2544 * copy_remote_class_key:
2546 * Make a copy of KEY in the domain and return the copy.
2549 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2551 MONO_REQ_GC_NEUTRAL_MODE
2553 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2554 gpointer *mp_key = (gpointer *)mono_domain_alloc (domain, key_size);
2556 memcpy (mp_key, key, key_size);
2562 * mono_remote_class:
2563 * @domain: the application domain
2564 * @class_name: name of the remote class
2566 * Creates and initializes a MonoRemoteClass object for a remote type.
2568 * Can raise an exception on failure.
2571 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2573 MONO_REQ_GC_UNSAFE_MODE;
2576 MonoRemoteClass *rc;
2577 gpointer* key, *mp_key;
2580 key = create_remote_class_key (NULL, proxy_class);
2582 mono_domain_lock (domain);
2583 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2587 mono_domain_unlock (domain);
2591 name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
2592 if (!mono_error_ok (&error)) {
2594 mono_domain_unlock (domain);
2595 mono_error_raise_exception (&error);
2598 mp_key = copy_remote_class_key (domain, key);
2602 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2603 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2604 rc->interface_count = 1;
2605 rc->interfaces [0] = proxy_class;
2606 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2608 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2609 rc->interface_count = 0;
2610 rc->proxy_class = proxy_class;
2613 rc->default_vtable = NULL;
2614 rc->xdomain_vtable = NULL;
2615 rc->proxy_class_name = name;
2616 #ifndef DISABLE_PERFCOUNTERS
2617 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2620 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2622 mono_domain_unlock (domain);
2627 * clone_remote_class:
2628 * Creates a copy of the remote_class, adding the provided class or interface
2630 static MonoRemoteClass*
2631 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2633 MONO_REQ_GC_NEUTRAL_MODE;
2635 MonoRemoteClass *rc;
2636 gpointer* key, *mp_key;
2638 key = create_remote_class_key (remote_class, extra_class);
2639 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2645 mp_key = copy_remote_class_key (domain, key);
2649 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2651 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2652 rc->proxy_class = remote_class->proxy_class;
2653 rc->interface_count = remote_class->interface_count + 1;
2655 // Keep the list of interfaces sorted, since the hash key of
2656 // the remote class depends on this
2657 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2658 if (remote_class->interfaces [i] > extra_class && i == j)
2659 rc->interfaces [j++] = extra_class;
2660 rc->interfaces [j] = remote_class->interfaces [i];
2663 rc->interfaces [j] = extra_class;
2665 // Replace the old class. The interface array is the same
2666 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2667 rc->proxy_class = extra_class;
2668 rc->interface_count = remote_class->interface_count;
2669 if (rc->interface_count > 0)
2670 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2673 rc->default_vtable = NULL;
2674 rc->xdomain_vtable = NULL;
2675 rc->proxy_class_name = remote_class->proxy_class_name;
2677 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2683 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2685 MONO_REQ_GC_UNSAFE_MODE;
2687 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2688 mono_domain_lock (domain);
2689 if (rp->target_domain_id != -1) {
2690 if (remote_class->xdomain_vtable == NULL)
2691 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2692 mono_domain_unlock (domain);
2693 mono_loader_unlock ();
2694 return remote_class->xdomain_vtable;
2696 if (remote_class->default_vtable == NULL) {
2699 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2700 klass = mono_class_from_mono_type (type);
2702 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)))
2703 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2706 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2709 mono_domain_unlock (domain);
2710 mono_loader_unlock ();
2711 return remote_class->default_vtable;
2715 * mono_upgrade_remote_class:
2716 * @domain: the application domain
2717 * @tproxy: the proxy whose remote class has to be upgraded.
2718 * @klass: class to which the remote class can be casted.
2720 * Updates the vtable of the remote class by adding the necessary method slots
2721 * and interface offsets so it can be safely casted to klass. klass can be a
2722 * class or an interface.
2725 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2727 MONO_REQ_GC_UNSAFE_MODE;
2729 MonoTransparentProxy *tproxy;
2730 MonoRemoteClass *remote_class;
2731 gboolean redo_vtable;
2733 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2734 mono_domain_lock (domain);
2736 tproxy = (MonoTransparentProxy*) proxy_object;
2737 remote_class = tproxy->remote_class;
2739 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2742 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2743 if (remote_class->interfaces [i] == klass)
2744 redo_vtable = FALSE;
2747 redo_vtable = (remote_class->proxy_class != klass);
2751 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2752 proxy_object->vtable = (MonoVTable *)mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2755 mono_domain_unlock (domain);
2756 mono_loader_unlock ();
2758 #endif /* DISABLE_REMOTING */
2762 * mono_object_get_virtual_method:
2763 * @obj: object to operate on.
2766 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2767 * the instance of a callvirt of method.
2770 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2772 MONO_REQ_GC_UNSAFE_MODE;
2775 MonoMethod **vtable;
2776 gboolean is_proxy = FALSE;
2777 MonoMethod *res = NULL;
2779 klass = mono_object_class (obj);
2780 #ifndef DISABLE_REMOTING
2781 if (klass == mono_defaults.transparent_proxy_class) {
2782 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2787 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2790 mono_class_setup_vtable (klass);
2791 vtable = klass->vtable;
2793 if (method->slot == -1) {
2794 /* method->slot might not be set for instances of generic methods */
2795 if (method->is_inflated) {
2796 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2797 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2800 g_assert_not_reached ();
2804 /* check method->slot is a valid index: perform isinstance? */
2805 if (method->slot != -1) {
2806 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2808 gboolean variance_used = FALSE;
2809 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2810 g_assert (iface_offset > 0);
2811 res = vtable [iface_offset + method->slot];
2814 res = vtable [method->slot];
2818 #ifndef DISABLE_REMOTING
2820 /* It may be an interface, abstract class method or generic method */
2821 if (!res || mono_method_signature (res)->generic_param_count)
2824 /* generic methods demand invoke_with_check */
2825 if (mono_method_signature (res)->generic_param_count)
2826 res = mono_marshal_get_remoting_invoke_with_check (res);
2829 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2830 res = mono_cominterop_get_invoke (res);
2833 res = mono_marshal_get_remoting_invoke (res);
2838 if (method->is_inflated) {
2840 /* Have to inflate the result */
2841 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, &error);
2842 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
2852 do_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2854 MONO_REQ_GC_UNSAFE_MODE;
2856 MonoObject *result = NULL;
2858 g_assert (callbacks.runtime_invoke);
2860 mono_error_init (error);
2862 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2863 mono_profiler_method_start_invoke (method);
2865 MONO_PREPARE_RESET_BLOCKING;
2867 result = callbacks.runtime_invoke (method, obj, params, exc, error);
2869 MONO_FINISH_RESET_BLOCKING;
2871 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2872 mono_profiler_method_end_invoke (method);
2874 if (!mono_error_ok (error))
2881 * mono_runtime_invoke:
2882 * @method: method to invoke
2883 * @obJ: object instance
2884 * @params: arguments to the method
2885 * @exc: exception information.
2887 * Invokes the method represented by @method on the object @obj.
2889 * obj is the 'this' pointer, it should be NULL for static
2890 * methods, a MonoObject* for object instances and a pointer to
2891 * the value type for value types.
2893 * The params array contains the arguments to the method with the
2894 * same convention: MonoObject* pointers for object instances and
2895 * pointers to the value type otherwise.
2897 * From unmanaged code you'll usually use the
2898 * mono_runtime_invoke() variant.
2900 * Note that this function doesn't handle virtual methods for
2901 * you, it will exec the exact method you pass: we still need to
2902 * expose a function to lookup the derived class implementation
2903 * of a virtual method (there are examples of this in the code,
2906 * You can pass NULL as the exc argument if you don't want to
2907 * catch exceptions, otherwise, *exc will be set to the exception
2908 * thrown, if any. if an exception is thrown, you can't use the
2909 * MonoObject* result from the function.
2911 * If the method returns a value type, it is boxed in an object
2915 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2920 res = mono_runtime_try_invoke (method, obj, params, exc, &error);
2921 if (*exc == NULL && !mono_error_ok(&error)) {
2922 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
2924 mono_error_cleanup (&error);
2926 res = mono_runtime_invoke_checked (method, obj, params, &error);
2927 mono_error_raise_exception (&error);
2933 * mono_runtime_try_invoke:
2934 * @method: method to invoke
2935 * @obJ: object instance
2936 * @params: arguments to the method
2937 * @exc: exception information.
2938 * @error: set on error
2940 * Invokes the method represented by @method on the object @obj.
2942 * obj is the 'this' pointer, it should be NULL for static
2943 * methods, a MonoObject* for object instances and a pointer to
2944 * the value type for value types.
2946 * The params array contains the arguments to the method with the
2947 * same convention: MonoObject* pointers for object instances and
2948 * pointers to the value type otherwise.
2950 * From unmanaged code you'll usually use the
2951 * mono_runtime_invoke() variant.
2953 * Note that this function doesn't handle virtual methods for
2954 * you, it will exec the exact method you pass: we still need to
2955 * expose a function to lookup the derived class implementation
2956 * of a virtual method (there are examples of this in the code,
2959 * For this function, you must not pass NULL as the exc argument if
2960 * you don't want to catch exceptions, use
2961 * mono_runtime_invoke_checked(). If an exception is thrown, you
2962 * can't use the MonoObject* result from the function.
2964 * If this method cannot be invoked, @error will be set and @exc and
2965 * the return value must not be used.
2967 * If the method returns a value type, it is boxed in an object
2971 mono_runtime_try_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError* error)
2973 MONO_REQ_GC_UNSAFE_MODE;
2975 g_assert (exc != NULL);
2977 if (mono_runtime_get_no_exec ())
2978 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2980 return do_runtime_invoke (method, obj, params, exc, error);
2984 * mono_runtime_invoke_checked:
2985 * @method: method to invoke
2986 * @obJ: object instance
2987 * @params: arguments to the method
2988 * @error: set on error
2990 * Invokes the method represented by @method on the object @obj.
2992 * obj is the 'this' pointer, it should be NULL for static
2993 * methods, a MonoObject* for object instances and a pointer to
2994 * the value type for value types.
2996 * The params array contains the arguments to the method with the
2997 * same convention: MonoObject* pointers for object instances and
2998 * pointers to the value type otherwise.
3000 * From unmanaged code you'll usually use the
3001 * mono_runtime_invoke() variant.
3003 * Note that this function doesn't handle virtual methods for
3004 * you, it will exec the exact method you pass: we still need to
3005 * expose a function to lookup the derived class implementation
3006 * of a virtual method (there are examples of this in the code,
3009 * If an exception is thrown, you can't use the MonoObject* result
3010 * from the function.
3012 * If this method cannot be invoked, @error will be set. If the
3013 * method throws an exception (and we're in coop mode) the exception
3014 * will be set in @error.
3016 * If the method returns a value type, it is boxed in an object
3020 mono_runtime_invoke_checked (MonoMethod *method, void *obj, void **params, MonoError* error)
3022 MONO_REQ_GC_UNSAFE_MODE;
3024 if (mono_runtime_get_no_exec ())
3025 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
3027 return do_runtime_invoke (method, obj, params, NULL, error);
3031 * mono_method_get_unmanaged_thunk:
3032 * @method: method to generate a thunk for.
3034 * Returns an unmanaged->managed thunk that can be used to call
3035 * a managed method directly from C.
3037 * The thunk's C signature closely matches the managed signature:
3039 * C#: public bool Equals (object obj);
3040 * C: typedef MonoBoolean (*Equals)(MonoObject*,
3041 * MonoObject*, MonoException**);
3043 * The 1st ("this") parameter must not be used with static methods:
3045 * C#: public static bool ReferenceEquals (object a, object b);
3046 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
3049 * The last argument must be a non-null pointer of a MonoException* pointer.
3050 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
3051 * exception has been thrown in managed code. Otherwise it will point
3052 * to the MonoException* caught by the thunk. In this case, the result of
3053 * the thunk is undefined:
3055 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
3056 * MonoException *ex = NULL;
3057 * Equals func = mono_method_get_unmanaged_thunk (method);
3058 * MonoBoolean res = func (thisObj, objToCompare, &ex);
3060 * // handle exception
3063 * The calling convention of the thunk matches the platform's default
3064 * convention. This means that under Windows, C declarations must
3065 * contain the __stdcall attribute:
3067 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
3068 * MonoObject*, MonoException**);
3072 * Value type arguments and return values are treated as they were objects:
3074 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
3075 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
3077 * Arguments must be properly boxed upon trunk's invocation, while return
3078 * values must be unboxed.
3081 mono_method_get_unmanaged_thunk (MonoMethod *method)
3083 MONO_REQ_GC_NEUTRAL_MODE;
3084 MONO_REQ_API_ENTRYPOINT;
3088 MONO_PREPARE_RESET_BLOCKING;
3089 method = mono_marshal_get_thunk_invoke_wrapper (method);
3090 res = mono_compile_method (method);
3091 MONO_FINISH_RESET_BLOCKING;
3097 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
3099 MONO_REQ_GC_UNSAFE_MODE;
3103 /* object fields cannot be byref, so we don't need a
3105 gpointer *p = (gpointer*)dest;
3112 case MONO_TYPE_BOOLEAN:
3114 case MONO_TYPE_U1: {
3115 guint8 *p = (guint8*)dest;
3116 *p = value ? *(guint8*)value : 0;
3121 case MONO_TYPE_CHAR: {
3122 guint16 *p = (guint16*)dest;
3123 *p = value ? *(guint16*)value : 0;
3126 #if SIZEOF_VOID_P == 4
3131 case MONO_TYPE_U4: {
3132 gint32 *p = (gint32*)dest;
3133 *p = value ? *(gint32*)value : 0;
3136 #if SIZEOF_VOID_P == 8
3141 case MONO_TYPE_U8: {
3142 gint64 *p = (gint64*)dest;
3143 *p = value ? *(gint64*)value : 0;
3146 case MONO_TYPE_R4: {
3147 float *p = (float*)dest;
3148 *p = value ? *(float*)value : 0;
3151 case MONO_TYPE_R8: {
3152 double *p = (double*)dest;
3153 *p = value ? *(double*)value : 0;
3156 case MONO_TYPE_STRING:
3157 case MONO_TYPE_SZARRAY:
3158 case MONO_TYPE_CLASS:
3159 case MONO_TYPE_OBJECT:
3160 case MONO_TYPE_ARRAY:
3161 mono_gc_wbarrier_generic_store (dest, deref_pointer ? *(MonoObject **)value : (MonoObject *)value);
3163 case MONO_TYPE_FNPTR:
3164 case MONO_TYPE_PTR: {
3165 gpointer *p = (gpointer*)dest;
3166 *p = deref_pointer? *(gpointer*)value: value;
3169 case MONO_TYPE_VALUETYPE:
3170 /* note that 't' and 'type->type' can be different */
3171 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3172 t = mono_class_enum_basetype (type->data.klass)->type;
3175 MonoClass *klass = mono_class_from_mono_type (type);
3176 int size = mono_class_value_size (klass, NULL);
3178 mono_gc_bzero_atomic (dest, size);
3180 mono_gc_wbarrier_value_copy (dest, value, 1, klass);
3183 case MONO_TYPE_GENERICINST:
3184 t = type->data.generic_class->container_class->byval_arg.type;
3187 g_error ("got type %x", type->type);
3192 * mono_field_set_value:
3193 * @obj: Instance object
3194 * @field: MonoClassField describing the field to set
3195 * @value: The value to be set
3197 * Sets the value of the field described by @field in the object instance @obj
3198 * to the value passed in @value. This method should only be used for instance
3199 * fields. For static fields, use mono_field_static_set_value.
3201 * The value must be on the native format of the field type.
3204 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3206 MONO_REQ_GC_UNSAFE_MODE;
3210 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3212 dest = (char*)obj + field->offset;
3213 mono_copy_value (field->type, dest, value, FALSE);
3217 * mono_field_static_set_value:
3218 * @field: MonoClassField describing the field to set
3219 * @value: The value to be set
3221 * Sets the value of the static field described by @field
3222 * to the value passed in @value.
3224 * The value must be on the native format of the field type.
3227 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3229 MONO_REQ_GC_UNSAFE_MODE;
3233 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3234 /* you cant set a constant! */
3235 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3237 if (field->offset == -1) {
3238 /* Special static */
3241 mono_domain_lock (vt->domain);
3242 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3243 mono_domain_unlock (vt->domain);
3244 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3246 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3248 mono_copy_value (field->type, dest, value, FALSE);
3252 * mono_vtable_get_static_field_data:
3254 * Internal use function: return a pointer to the memory holding the static fields
3255 * for a class or NULL if there are no static fields.
3256 * This is exported only for use by the debugger.
3259 mono_vtable_get_static_field_data (MonoVTable *vt)
3261 MONO_REQ_GC_NEUTRAL_MODE
3263 if (!vt->has_static_fields)
3265 return vt->vtable [vt->klass->vtable_size];
3269 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3271 MONO_REQ_GC_UNSAFE_MODE;
3275 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3276 if (field->offset == -1) {
3277 /* Special static */
3280 mono_domain_lock (vt->domain);
3281 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3282 mono_domain_unlock (vt->domain);
3283 src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3285 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3288 src = (guint8*)obj + field->offset;
3295 * mono_field_get_value:
3296 * @obj: Object instance
3297 * @field: MonoClassField describing the field to fetch information from
3298 * @value: pointer to the location where the value will be stored
3300 * Use this routine to get the value of the field @field in the object
3303 * The pointer provided by value must be of the field type, for reference
3304 * types this is a MonoObject*, for value types its the actual pointer to
3309 * mono_field_get_value (obj, int_field, &i);
3312 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3314 MONO_REQ_GC_UNSAFE_MODE;
3320 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3322 src = (char*)obj + field->offset;
3323 mono_copy_value (field->type, value, src, TRUE);
3327 * mono_field_get_value_object:
3328 * @domain: domain where the object will be created (if boxing)
3329 * @field: MonoClassField describing the field to fetch information from
3330 * @obj: The object instance for the field.
3332 * Returns: a new MonoObject with the value from the given field. If the
3333 * field represents a value type, the value is boxed.
3337 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3339 MONO_REQ_GC_UNSAFE_MODE;
3344 MonoVTable *vtable = NULL;
3346 gboolean is_static = FALSE;
3347 gboolean is_ref = FALSE;
3348 gboolean is_literal = FALSE;
3349 gboolean is_ptr = FALSE;
3350 MonoType *type = mono_field_get_type_checked (field, &error);
3352 if (!mono_error_ok (&error))
3353 mono_error_raise_exception (&error);
3355 switch (type->type) {
3356 case MONO_TYPE_STRING:
3357 case MONO_TYPE_OBJECT:
3358 case MONO_TYPE_CLASS:
3359 case MONO_TYPE_ARRAY:
3360 case MONO_TYPE_SZARRAY:
3365 case MONO_TYPE_BOOLEAN:
3368 case MONO_TYPE_CHAR:
3377 case MONO_TYPE_VALUETYPE:
3378 is_ref = type->byref;
3380 case MONO_TYPE_GENERICINST:
3381 is_ref = !mono_type_generic_inst_is_valuetype (type);
3387 g_error ("type 0x%x not handled in "
3388 "mono_field_get_value_object", type->type);
3392 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3395 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3399 vtable = mono_class_vtable_full (domain, field->parent, TRUE);
3400 if (!vtable->initialized)
3401 mono_runtime_class_init (vtable);
3409 get_default_field_value (domain, field, &o);
3410 } else if (is_static) {
3411 mono_field_static_get_value (vtable, field, &o);
3413 mono_field_get_value (obj, field, &o);
3419 static MonoMethod *m;
3425 MonoClass *ptr_klass = mono_class_get_pointer_class ();
3426 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3432 get_default_field_value (domain, field, v);
3433 } else if (is_static) {
3434 mono_field_static_get_value (vtable, field, v);
3436 mono_field_get_value (obj, field, v);
3439 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3440 args [0] = ptr ? *ptr : NULL;
3441 args [1] = mono_type_get_object_checked (mono_domain_get (), type, &error);
3442 mono_error_raise_exception (&error); /* FIXME don't raise here */
3444 o = mono_runtime_invoke_checked (m, NULL, args, &error);
3445 mono_error_raise_exception (&error); /* FIXME don't raise here */
3450 /* boxed value type */
3451 klass = mono_class_from_mono_type (type);
3453 if (mono_class_is_nullable (klass))
3454 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
3456 o = mono_object_new_checked (domain, klass, &error);
3457 mono_error_raise_exception (&error); /* FIXME don't raise here */
3458 v = ((gchar *) o) + sizeof (MonoObject);
3461 get_default_field_value (domain, field, v);
3462 } else if (is_static) {
3463 mono_field_static_get_value (vtable, field, v);
3465 mono_field_get_value (obj, field, v);
3472 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
3474 MONO_REQ_GC_UNSAFE_MODE;
3477 const char *p = blob;
3478 mono_metadata_decode_blob_size (p, &p);
3481 case MONO_TYPE_BOOLEAN:
3484 *(guint8 *) value = *p;
3486 case MONO_TYPE_CHAR:
3489 *(guint16*) value = read16 (p);
3493 *(guint32*) value = read32 (p);
3497 *(guint64*) value = read64 (p);
3500 readr4 (p, (float*) value);
3503 readr8 (p, (double*) value);
3505 case MONO_TYPE_STRING:
3506 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3508 case MONO_TYPE_CLASS:
3509 *(gpointer*) value = NULL;
3513 g_warning ("type 0x%02x should not be in constant table", type);
3519 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3521 MONO_REQ_GC_NEUTRAL_MODE;
3523 MonoTypeEnum def_type;
3526 data = mono_class_get_field_default_value (field, &def_type);
3527 mono_get_constant_value_from_blob (domain, def_type, data, value);
3531 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value)
3533 MONO_REQ_GC_UNSAFE_MODE;
3537 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3539 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3540 get_default_field_value (vt->domain, field, value);
3544 if (field->offset == -1) {
3545 /* Special static */
3546 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3547 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3549 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3551 mono_copy_value (field->type, value, src, TRUE);
3555 * mono_field_static_get_value:
3556 * @vt: vtable to the object
3557 * @field: MonoClassField describing the field to fetch information from
3558 * @value: where the value is returned
3560 * Use this routine to get the value of the static field @field value.
3562 * The pointer provided by value must be of the field type, for reference
3563 * types this is a MonoObject*, for value types its the actual pointer to
3568 * mono_field_static_get_value (vt, int_field, &i);
3571 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3573 MONO_REQ_GC_NEUTRAL_MODE;
3575 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value);
3579 * mono_property_set_value:
3580 * @prop: MonoProperty to set
3581 * @obj: instance object on which to act
3582 * @params: parameters to pass to the propery
3583 * @exc: optional exception
3585 * Invokes the property's set method with the given arguments on the
3586 * object instance obj (or NULL for static properties).
3588 * You can pass NULL as the exc argument if you don't want to
3589 * catch exceptions, otherwise, *exc will be set to the exception
3590 * thrown, if any. if an exception is thrown, you can't use the
3591 * MonoObject* result from the function.
3594 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3596 MONO_REQ_GC_UNSAFE_MODE;
3599 do_runtime_invoke (prop->set, obj, params, exc, &error);
3600 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3601 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3603 mono_error_raise_exception (&error); /* FIXME don't raise here */
3608 * mono_property_get_value:
3609 * @prop: MonoProperty to fetch
3610 * @obj: instance object on which to act
3611 * @params: parameters to pass to the propery
3612 * @exc: optional exception
3614 * Invokes the property's get method with the given arguments on the
3615 * object instance obj (or NULL for static properties).
3617 * You can pass NULL as the exc argument if you don't want to
3618 * catch exceptions, otherwise, *exc will be set to the exception
3619 * thrown, if any. if an exception is thrown, you can't use the
3620 * MonoObject* result from the function.
3622 * Returns: the value from invoking the get method on the property.
3625 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3627 MONO_REQ_GC_UNSAFE_MODE;
3630 MonoObject *val = do_runtime_invoke (prop->get, obj, params, exc, &error);
3631 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3632 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3634 mono_error_raise_exception (&error); /* FIXME don't raise here */
3641 * mono_nullable_init:
3642 * @buf: The nullable structure to initialize.
3643 * @value: the value to initialize from
3644 * @klass: the type for the object
3646 * Initialize the nullable structure pointed to by @buf from @value which
3647 * should be a boxed value type. The size of @buf should be able to hold
3648 * as much data as the @klass->instance_size (which is the number of bytes
3649 * that will be copies).
3651 * Since Nullables have variable structure, we can not define a C
3652 * structure for them.
3655 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3657 MONO_REQ_GC_UNSAFE_MODE;
3659 MonoClass *param_class = klass->cast_class;
3661 mono_class_setup_fields_locking (klass);
3662 g_assert (klass->fields_inited);
3664 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3665 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3667 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3669 if (param_class->has_references)
3670 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3672 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3674 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3679 * mono_nullable_box:
3680 * @buf: The buffer representing the data to be boxed
3681 * @klass: the type to box it as.
3683 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3687 mono_nullable_box (guint8 *buf, MonoClass *klass)
3689 MONO_REQ_GC_UNSAFE_MODE;
3693 MonoClass *param_class = klass->cast_class;
3695 mono_class_setup_fields_locking (klass);
3696 g_assert (klass->fields_inited);
3698 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3699 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3701 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3702 MonoObject *o = mono_object_new_checked (mono_domain_get (), param_class, &error);
3703 mono_error_raise_exception (&error); /* FIXME don't raise here */
3704 if (param_class->has_references)
3705 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3707 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3715 * mono_get_delegate_invoke:
3716 * @klass: The delegate class
3718 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3721 mono_get_delegate_invoke (MonoClass *klass)
3723 MONO_REQ_GC_NEUTRAL_MODE;
3727 /* This is called at runtime, so avoid the slower search in metadata */
3728 mono_class_setup_methods (klass);
3729 if (mono_class_has_failure (klass))
3731 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3736 * mono_get_delegate_begin_invoke:
3737 * @klass: The delegate class
3739 * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3742 mono_get_delegate_begin_invoke (MonoClass *klass)
3744 MONO_REQ_GC_NEUTRAL_MODE;
3748 /* This is called at runtime, so avoid the slower search in metadata */
3749 mono_class_setup_methods (klass);
3750 if (mono_class_has_failure (klass))
3752 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3757 * mono_get_delegate_end_invoke:
3758 * @klass: The delegate class
3760 * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3763 mono_get_delegate_end_invoke (MonoClass *klass)
3765 MONO_REQ_GC_NEUTRAL_MODE;
3769 /* This is called at runtime, so avoid the slower search in metadata */
3770 mono_class_setup_methods (klass);
3771 if (mono_class_has_failure (klass))
3773 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3778 * mono_runtime_delegate_invoke:
3779 * @delegate: pointer to a delegate object.
3780 * @params: parameters for the delegate.
3781 * @exc: Pointer to the exception result.
3783 * Invokes the delegate method @delegate with the parameters provided.
3785 * You can pass NULL as the exc argument if you don't want to
3786 * catch exceptions, otherwise, *exc will be set to the exception
3787 * thrown, if any. if an exception is thrown, you can't use the
3788 * MonoObject* result from the function.
3791 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3793 MONO_REQ_GC_UNSAFE_MODE;
3797 MonoClass *klass = delegate->vtable->klass;
3800 im = mono_get_delegate_invoke (klass);
3802 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3805 o = mono_runtime_try_invoke (im, delegate, params, exc, &error);
3806 if (*exc == NULL && !mono_error_ok (&error))
3807 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3809 mono_error_cleanup (&error);
3811 o = mono_runtime_invoke_checked (im, delegate, params, &error);
3812 mono_error_raise_exception (&error); /* FIXME don't raise here */
3818 static char **main_args = NULL;
3819 static int num_main_args = 0;
3822 * mono_runtime_get_main_args:
3824 * Returns: a MonoArray with the arguments passed to the main program
3827 mono_runtime_get_main_args (void)
3829 MONO_REQ_GC_UNSAFE_MODE;
3833 MonoDomain *domain = mono_domain_get ();
3835 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3837 for (i = 0; i < num_main_args; ++i)
3838 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3844 free_main_args (void)
3846 MONO_REQ_GC_NEUTRAL_MODE;
3850 for (i = 0; i < num_main_args; ++i)
3851 g_free (main_args [i]);
3858 * mono_runtime_set_main_args:
3859 * @argc: number of arguments from the command line
3860 * @argv: array of strings from the command line
3862 * Set the command line arguments from an embedding application that doesn't otherwise call
3863 * mono_runtime_run_main ().
3866 mono_runtime_set_main_args (int argc, char* argv[])
3868 MONO_REQ_GC_NEUTRAL_MODE;
3873 main_args = g_new0 (char*, argc);
3874 num_main_args = argc;
3876 for (i = 0; i < argc; ++i) {
3879 utf8_arg = mono_utf8_from_external (argv[i]);
3880 if (utf8_arg == NULL) {
3881 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
3882 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3886 main_args [i] = utf8_arg;
3893 * mono_runtime_run_main:
3894 * @method: the method to start the application with (usually Main)
3895 * @argc: number of arguments from the command line
3896 * @argv: array of strings from the command line
3897 * @exc: excetption results
3899 * Execute a standard Main() method (argc/argv contains the
3900 * executable name). This method also sets the command line argument value
3901 * needed by System.Environment.
3906 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3909 MONO_REQ_GC_UNSAFE_MODE;
3912 MonoArray *args = NULL;
3913 MonoDomain *domain = mono_domain_get ();
3914 gchar *utf8_fullpath;
3915 MonoMethodSignature *sig;
3917 g_assert (method != NULL);
3919 mono_thread_set_main (mono_thread_current ());
3921 main_args = g_new0 (char*, argc);
3922 num_main_args = argc;
3924 if (!g_path_is_absolute (argv [0])) {
3925 gchar *basename = g_path_get_basename (argv [0]);
3926 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3930 utf8_fullpath = mono_utf8_from_external (fullpath);
3931 if(utf8_fullpath == NULL) {
3932 /* Printing the arg text will cause glib to
3933 * whinge about "Invalid UTF-8", but at least
3934 * its relevant, and shows the problem text
3937 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3938 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3945 utf8_fullpath = mono_utf8_from_external (argv[0]);
3946 if(utf8_fullpath == NULL) {
3947 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3948 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3953 main_args [0] = utf8_fullpath;
3955 for (i = 1; i < argc; ++i) {
3958 utf8_arg=mono_utf8_from_external (argv[i]);
3959 if(utf8_arg==NULL) {
3960 /* Ditto the comment about Invalid UTF-8 here */
3961 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3962 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3966 main_args [i] = utf8_arg;
3971 sig = mono_method_signature (method);
3973 g_print ("Unable to load Main method.\n");
3977 if (sig->param_count) {
3978 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3979 for (i = 0; i < argc; ++i) {
3980 /* The encodings should all work, given that
3981 * we've checked all these args for the
3984 gchar *str = mono_utf8_from_external (argv [i]);
3985 MonoString *arg = mono_string_new (domain, str);
3986 mono_array_setref (args, i, arg);
3990 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3993 mono_assembly_set_main (method->klass->image->assembly);
3995 return mono_runtime_exec_main (method, args, exc);
3999 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4001 static MonoMethod *serialize_method;
4007 if (!serialize_method) {
4008 MonoClass *klass = mono_class_get_remoting_services_class ();
4009 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
4012 if (!serialize_method) {
4017 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
4022 array = mono_runtime_try_invoke (serialize_method, NULL, params, exc, &error);
4023 if (*exc == NULL && !mono_error_ok (&error))
4024 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert serialize_object to MonoError */
4026 mono_error_cleanup (&error);
4035 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4037 MONO_REQ_GC_UNSAFE_MODE;
4039 static MonoMethod *deserialize_method;
4045 if (!deserialize_method) {
4046 MonoClass *klass = mono_class_get_remoting_services_class ();
4047 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
4049 if (!deserialize_method) {
4057 result = mono_runtime_try_invoke (deserialize_method, NULL, params, exc, &error);
4058 if (*exc == NULL && !mono_error_ok (&error))
4059 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert deserialize_object to MonoError */
4061 mono_error_cleanup (&error);
4069 #ifndef DISABLE_REMOTING
4071 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
4073 MONO_REQ_GC_UNSAFE_MODE;
4075 static MonoMethod *get_proxy_method;
4078 MonoDomain *domain = mono_domain_get ();
4079 MonoRealProxy *real_proxy;
4080 MonoReflectionType *reflection_type;
4081 MonoTransparentProxy *transparent_proxy;
4083 if (!get_proxy_method)
4084 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
4086 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
4088 real_proxy = (MonoRealProxy*) mono_object_new_checked (domain, mono_defaults.real_proxy_class, &error);
4089 mono_error_raise_exception (&error); /* FIXME don't raise here */
4090 reflection_type = mono_type_get_object_checked (domain, &obj->vtable->klass->byval_arg, &error);
4091 mono_error_raise_exception (&error); /* FIXME don't raise here */
4093 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
4094 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
4098 transparent_proxy = (MonoTransparentProxy*) mono_runtime_try_invoke (get_proxy_method, real_proxy, NULL, exc, &error);
4099 if (*exc == NULL && !mono_error_ok (&error))
4100 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME change make_transparent_proxy outarg to MonoError */
4102 mono_error_cleanup (&error);
4106 return (MonoObject*) transparent_proxy;
4108 #endif /* DISABLE_REMOTING */
4111 * mono_object_xdomain_representation
4113 * @target_domain: a domain
4114 * @exc: pointer to a MonoObject*
4116 * Creates a representation of obj in the domain target_domain. This
4117 * is either a copy of obj arrived through via serialization and
4118 * deserialization or a proxy, depending on whether the object is
4119 * serializable or marshal by ref. obj must not be in target_domain.
4121 * If the object cannot be represented in target_domain, NULL is
4122 * returned and *exc is set to an appropriate exception.
4125 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
4127 MONO_REQ_GC_UNSAFE_MODE;
4129 MonoObject *deserialized = NULL;
4130 gboolean failure = FALSE;
4132 g_assert (exc != NULL);
4135 #ifndef DISABLE_REMOTING
4136 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
4137 deserialized = make_transparent_proxy (obj, &failure, exc);
4142 MonoDomain *domain = mono_domain_get ();
4143 MonoObject *serialized;
4145 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
4146 serialized = serialize_object (obj, &failure, exc);
4147 mono_domain_set_internal_with_options (target_domain, FALSE);
4149 deserialized = deserialize_object (serialized, &failure, exc);
4150 if (domain != target_domain)
4151 mono_domain_set_internal_with_options (domain, FALSE);
4154 return deserialized;
4157 /* Used in call_unhandled_exception_delegate */
4159 create_unhandled_exception_eventargs (MonoObject *exc)
4161 MONO_REQ_GC_UNSAFE_MODE;
4166 MonoMethod *method = NULL;
4167 MonoBoolean is_terminating = TRUE;
4170 klass = mono_class_get_unhandled_exception_event_args_class ();
4171 mono_class_init (klass);
4173 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4174 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
4178 args [1] = &is_terminating;
4180 obj = mono_object_new_checked (mono_domain_get (), klass, &error);
4181 mono_error_raise_exception (&error); /* FIXME don't raise here */
4183 mono_runtime_invoke_checked (method, obj, args, &error);
4184 mono_error_raise_exception (&error); /* FIXME don't raise here */
4189 /* Used in mono_unhandled_exception */
4191 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4192 MONO_REQ_GC_UNSAFE_MODE;
4194 MonoObject *e = NULL;
4196 MonoDomain *current_domain = mono_domain_get ();
4198 if (domain != current_domain)
4199 mono_domain_set_internal_with_options (domain, FALSE);
4201 g_assert (domain == mono_object_domain (domain->domain));
4203 if (mono_object_domain (exc) != domain) {
4204 MonoObject *serialization_exc;
4206 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
4208 if (serialization_exc) {
4210 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
4213 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4214 "System.Runtime.Serialization", "SerializationException",
4215 "Could not serialize unhandled exception.");
4219 g_assert (mono_object_domain (exc) == domain);
4221 pa [0] = domain->domain;
4222 pa [1] = create_unhandled_exception_eventargs (exc);
4223 mono_runtime_delegate_invoke (delegate, pa, &e);
4225 if (domain != current_domain)
4226 mono_domain_set_internal_with_options (current_domain, FALSE);
4230 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4231 if (!mono_error_ok (&error)) {
4232 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4233 mono_error_cleanup (&error);
4235 g_warning ("exception inside UnhandledException handler: %s\n", msg);
4241 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4244 * mono_runtime_unhandled_exception_policy_set:
4245 * @policy: the new policy
4247 * This is a VM internal routine.
4249 * Sets the runtime policy for handling unhandled exceptions.
4252 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4253 runtime_unhandled_exception_policy = policy;
4257 * mono_runtime_unhandled_exception_policy_get:
4259 * This is a VM internal routine.
4261 * Gets the runtime policy for handling unhandled exceptions.
4263 MonoRuntimeUnhandledExceptionPolicy
4264 mono_runtime_unhandled_exception_policy_get (void) {
4265 return runtime_unhandled_exception_policy;
4269 * mono_unhandled_exception:
4270 * @exc: exception thrown
4272 * This is a VM internal routine.
4274 * We call this function when we detect an unhandled exception
4275 * in the default domain.
4277 * It invokes the * UnhandledException event in AppDomain or prints
4278 * a warning to the console
4281 mono_unhandled_exception (MonoObject *exc)
4283 MONO_REQ_GC_UNSAFE_MODE;
4285 MonoClassField *field;
4286 MonoDomain *current_domain, *root_domain;
4287 MonoObject *current_appdomain_delegate = NULL, *root_appdomain_delegate = NULL;
4289 if (mono_class_has_parent (exc->vtable->klass, mono_defaults.threadabortexception_class))
4292 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4295 current_domain = mono_domain_get ();
4296 root_domain = mono_get_root_domain ();
4298 root_appdomain_delegate = mono_field_get_value_object (root_domain, field, (MonoObject*) root_domain->domain);
4299 if (current_domain != root_domain)
4300 current_appdomain_delegate = mono_field_get_value_object (current_domain, field, (MonoObject*) current_domain->domain);
4302 /* set exitcode only if we will abort the process */
4303 if (!current_appdomain_delegate && !root_appdomain_delegate) {
4304 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4305 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4307 mono_environment_exitcode_set (1);
4310 mono_print_unhandled_exception (exc);
4312 if (root_appdomain_delegate)
4313 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4314 if (current_appdomain_delegate)
4315 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4320 * mono_runtime_exec_managed_code:
4321 * @domain: Application domain
4322 * @main_func: function to invoke from the execution thread
4323 * @main_args: parameter to the main_func
4325 * Launch a new thread to execute a function
4327 * main_func is called back from the thread with main_args as the
4328 * parameter. The callback function is expected to start Main()
4329 * eventually. This function then waits for all managed threads to
4331 * It is not necesseray anymore to execute managed code in a subthread,
4332 * so this function should not be used anymore by default: just
4333 * execute the code and then call mono_thread_manage ().
4336 mono_runtime_exec_managed_code (MonoDomain *domain,
4337 MonoMainThreadFunc main_func,
4340 mono_thread_create (domain, main_func, main_args);
4342 mono_thread_manage ();
4346 * Execute a standard Main() method (args doesn't contain the
4350 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4352 MONO_REQ_GC_UNSAFE_MODE;
4358 MonoCustomAttrInfo* cinfo;
4359 gboolean has_stathread_attribute;
4360 MonoInternalThread* thread = mono_thread_internal_current ();
4366 domain = mono_object_domain (args);
4367 if (!domain->entry_assembly) {
4369 MonoAssembly *assembly;
4371 assembly = method->klass->image->assembly;
4372 domain->entry_assembly = assembly;
4373 /* Domains created from another domain already have application_base and configuration_file set */
4374 if (domain->setup->application_base == NULL) {
4375 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4378 if (domain->setup->configuration_file == NULL) {
4379 str = g_strconcat (assembly->image->name, ".config", NULL);
4380 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4382 mono_domain_set_options_from_config (domain);
4386 cinfo = mono_custom_attrs_from_method (method);
4388 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, mono_class_get_sta_thread_attribute_class ());
4390 mono_custom_attrs_free (cinfo);
4392 has_stathread_attribute = FALSE;
4394 if (has_stathread_attribute) {
4395 thread->apartment_state = ThreadApartmentState_STA;
4397 thread->apartment_state = ThreadApartmentState_MTA;
4399 mono_thread_init_apartment_state ();
4401 /* FIXME: check signature of method */
4402 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4405 res = mono_runtime_try_invoke (method, NULL, pa, exc, &error);
4406 if (*exc == NULL && !mono_error_ok (&error))
4407 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4409 mono_error_cleanup (&error);
4411 res = mono_runtime_invoke_checked (method, NULL, pa, &error);
4412 mono_error_raise_exception (&error); /* FIXME don't raise here */
4416 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4420 mono_environment_exitcode_set (rval);
4423 mono_runtime_try_invoke (method, NULL, pa, exc, &error);
4424 if (*exc == NULL && !mono_error_ok (&error))
4425 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4427 mono_error_cleanup (&error);
4429 mono_runtime_invoke_checked (method, NULL, pa, &error);
4430 mono_error_raise_exception (&error); /* FIXME don't raise here */
4436 /* If the return type of Main is void, only
4437 * set the exitcode if an exception was thrown
4438 * (we don't want to blow away an
4439 * explicitly-set exit code)
4442 mono_environment_exitcode_set (rval);
4450 * mono_runtime_invoke_array:
4451 * @method: method to invoke
4452 * @obJ: object instance
4453 * @params: arguments to the method
4454 * @exc: exception information.
4456 * Invokes the method represented by @method on the object @obj.
4458 * obj is the 'this' pointer, it should be NULL for static
4459 * methods, a MonoObject* for object instances and a pointer to
4460 * the value type for value types.
4462 * The params array contains the arguments to the method with the
4463 * same convention: MonoObject* pointers for object instances and
4464 * pointers to the value type otherwise. The _invoke_array
4465 * variant takes a C# object[] as the params argument (MonoArray
4466 * *params): in this case the value types are boxed inside the
4467 * respective reference representation.
4469 * From unmanaged code you'll usually use the
4470 * mono_runtime_invoke_checked() variant.
4472 * Note that this function doesn't handle virtual methods for
4473 * you, it will exec the exact method you pass: we still need to
4474 * expose a function to lookup the derived class implementation
4475 * of a virtual method (there are examples of this in the code,
4478 * You can pass NULL as the exc argument if you don't want to
4479 * catch exceptions, otherwise, *exc will be set to the exception
4480 * thrown, if any. if an exception is thrown, you can't use the
4481 * MonoObject* result from the function.
4483 * If the method returns a value type, it is boxed in an object
4487 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4490 MONO_REQ_GC_UNSAFE_MODE;
4493 MonoMethodSignature *sig = mono_method_signature (method);
4494 gpointer *pa = NULL;
4497 gboolean has_byref_nullables = FALSE;
4499 if (NULL != params) {
4500 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
4501 for (i = 0; i < mono_array_length (params); i++) {
4502 MonoType *t = sig->params [i];
4508 case MONO_TYPE_BOOLEAN:
4511 case MONO_TYPE_CHAR:
4520 case MONO_TYPE_VALUETYPE:
4521 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
4522 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4523 pa [i] = mono_array_get (params, MonoObject*, i);
4525 has_byref_nullables = TRUE;
4527 /* MS seems to create the objects if a null is passed in */
4528 if (!mono_array_get (params, MonoObject*, i)) {
4529 MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (sig->params [i]), &error);
4530 mono_error_raise_exception (&error); /* FIXME don't raise here */
4531 mono_array_setref (params, i, o);
4536 * We can't pass the unboxed vtype byref to the callee, since
4537 * that would mean the callee would be able to modify boxed
4538 * primitive types. So we (and MS) make a copy of the boxed
4539 * object, pass that to the callee, and replace the original
4540 * boxed object in the arg array with the copy.
4542 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4543 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
4544 mono_array_setref (params, i, copy);
4547 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4550 case MONO_TYPE_STRING:
4551 case MONO_TYPE_OBJECT:
4552 case MONO_TYPE_CLASS:
4553 case MONO_TYPE_ARRAY:
4554 case MONO_TYPE_SZARRAY:
4556 pa [i] = mono_array_addr (params, MonoObject*, i);
4557 // FIXME: I need to check this code path
4559 pa [i] = mono_array_get (params, MonoObject*, i);
4561 case MONO_TYPE_GENERICINST:
4563 t = &t->data.generic_class->container_class->this_arg;
4565 t = &t->data.generic_class->container_class->byval_arg;
4567 case MONO_TYPE_PTR: {
4570 /* The argument should be an IntPtr */
4571 arg = mono_array_get (params, MonoObject*, i);
4575 g_assert (arg->vtable->klass == mono_defaults.int_class);
4576 pa [i] = ((MonoIntPtr*)arg)->m_value;
4581 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
4586 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4589 if (mono_class_is_nullable (method->klass)) {
4590 /* Need to create a boxed vtype instead */
4596 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
4600 obj = mono_object_new_checked (mono_domain_get (), method->klass, &error);
4601 g_assert (obj && mono_error_ok (&error)); /*maybe we should raise a TLE instead?*/ /* FIXME don't swallow error */
4602 #ifndef DISABLE_REMOTING
4603 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
4604 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
4607 if (method->klass->valuetype)
4608 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
4611 } else if (method->klass->valuetype) {
4612 obj = mono_value_box (mono_domain_get (), method->klass, obj);
4616 mono_runtime_try_invoke (method, o, pa, exc, &error);
4617 if (*exc == NULL && !mono_error_ok (&error))
4618 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4620 mono_error_cleanup (&error);
4622 mono_runtime_invoke_checked (method, o, pa, &error);
4623 mono_error_raise_exception (&error); /* FIXME don't raise here */
4626 return (MonoObject *)obj;
4628 if (mono_class_is_nullable (method->klass)) {
4629 MonoObject *nullable;
4631 /* Convert the unboxed vtype into a Nullable structure */
4632 nullable = mono_object_new_checked (mono_domain_get (), method->klass, &error);
4633 mono_error_raise_exception (&error); /* FIXME don't raise here */
4635 mono_nullable_init ((guint8 *)mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
4636 obj = mono_object_unbox (nullable);
4639 /* obj must be already unboxed if needed */
4641 res = mono_runtime_try_invoke (method, obj, pa, exc, &error);
4642 if (*exc == NULL && !mono_error_ok (&error))
4643 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4645 mono_error_cleanup (&error);
4647 res = mono_runtime_invoke_checked (method, obj, pa, &error);
4648 mono_error_raise_exception (&error); /* FIXME don't raise here */
4651 if (sig->ret->type == MONO_TYPE_PTR) {
4652 MonoClass *pointer_class;
4653 static MonoMethod *box_method;
4655 MonoObject *box_exc;
4658 * The runtime-invoke wrapper returns a boxed IntPtr, need to
4659 * convert it to a Pointer object.
4661 pointer_class = mono_class_get_pointer_class ();
4663 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4665 g_assert (res->vtable->klass == mono_defaults.int_class);
4666 box_args [0] = ((MonoIntPtr*)res)->m_value;
4667 box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, &error);
4668 mono_error_raise_exception (&error); /* FIXME don't raise here */
4670 res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, &error);
4671 g_assert (box_exc == NULL);
4672 mono_error_assert_ok (&error);
4675 if (has_byref_nullables) {
4677 * The runtime invoke wrapper already converted byref nullables back,
4678 * and stored them in pa, we just need to copy them back to the
4681 for (i = 0; i < mono_array_length (params); i++) {
4682 MonoType *t = sig->params [i];
4684 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4685 mono_array_setref (params, i, pa [i]);
4695 * @klass: the class of the object that we want to create
4697 * Returns: a newly created object whose definition is
4698 * looked up using @klass. This will not invoke any constructors,
4699 * so the consumer of this routine has to invoke any constructors on
4700 * its own to initialize the object.
4702 * It returns NULL on failure.
4705 mono_object_new (MonoDomain *domain, MonoClass *klass)
4707 MONO_REQ_GC_UNSAFE_MODE;
4711 MonoObject * result = mono_object_new_checked (domain, klass, &error);
4713 mono_error_raise_exception (&error);
4718 ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
4720 MONO_REQ_GC_UNSAFE_MODE;
4724 MonoObject * result = mono_object_new_checked (domain, klass, &error);
4726 mono_error_raise_exception (&error);
4731 * mono_object_new_checked:
4732 * @klass: the class of the object that we want to create
4733 * @error: set on error
4735 * Returns: a newly created object whose definition is
4736 * looked up using @klass. This will not invoke any constructors,
4737 * so the consumer of this routine has to invoke any constructors on
4738 * its own to initialize the object.
4740 * It returns NULL on failure and sets @error.
4743 mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
4745 MONO_REQ_GC_UNSAFE_MODE;
4749 vtable = mono_class_vtable (domain, klass);
4750 g_assert (vtable); /* FIXME don't swallow the error */
4752 MonoObject *o = mono_object_new_specific_checked (vtable, error);
4757 * mono_object_new_pinned:
4759 * Same as mono_object_new, but the returned object will be pinned.
4760 * For SGEN, these objects will only be freed at appdomain unload.
4763 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
4765 MONO_REQ_GC_UNSAFE_MODE;
4769 mono_error_init (error);
4771 vtable = mono_class_vtable (domain, klass);
4772 g_assert (vtable); /* FIXME don't swallow the error */
4774 MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
4776 if (G_UNLIKELY (!o))
4777 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
4778 else if (G_UNLIKELY (vtable->klass->has_finalize))
4779 mono_object_register_finalizer (o, error);
4785 * mono_object_new_specific:
4786 * @vtable: the vtable of the object that we want to create
4788 * Returns: A newly created object with class and domain specified
4792 mono_object_new_specific (MonoVTable *vtable)
4795 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
4796 mono_error_raise_exception (&error);
4802 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
4804 MONO_REQ_GC_UNSAFE_MODE;
4808 mono_error_init (error);
4810 /* check for is_com_object for COM Interop */
4811 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
4814 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4817 MonoClass *klass = mono_class_get_activation_services_class ();
4820 mono_class_init (klass);
4822 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4824 mono_error_set_generic_error (error, "System", "NotSupportedException", "Linked away.");
4827 vtable->domain->create_proxy_for_type_method = im;
4830 pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
4831 if (!mono_error_ok (error))
4834 o = mono_runtime_invoke_checked (im, NULL, pa, error);
4835 if (!mono_error_ok (error))
4842 return mono_object_new_alloc_specific_checked (vtable, error);
4846 ves_icall_object_new_specific (MonoVTable *vtable)
4849 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
4850 mono_error_raise_exception (&error);
4856 * mono_object_new_alloc_specific:
4857 * @vtable: virtual table for the object.
4859 * This function allocates a new `MonoObject` with the type derived
4860 * from the @vtable information. If the class of this object has a
4861 * finalizer, then the object will be tracked for finalization.
4863 * This method might raise an exception on errors. Use the
4864 * `mono_object_new_fast_checked` method if you want to manually raise
4867 * Returns: the allocated object.
4870 mono_object_new_alloc_specific (MonoVTable *vtable)
4873 MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
4874 mono_error_raise_exception (&error);
4880 * mono_object_new_alloc_specific_checked:
4881 * @vtable: virtual table for the object.
4882 * @error: holds the error return value.
4884 * This function allocates a new `MonoObject` with the type derived
4885 * from the @vtable information. If the class of this object has a
4886 * finalizer, then the object will be tracked for finalization.
4888 * If there is not enough memory, the @error parameter will be set
4889 * and will contain a user-visible message with the amount of bytes
4890 * that were requested.
4892 * Returns: the allocated object, or NULL if there is not enough memory
4896 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
4898 MONO_REQ_GC_UNSAFE_MODE;
4902 mono_error_init (error);
4904 o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
4906 if (G_UNLIKELY (!o))
4907 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
4908 else if (G_UNLIKELY (vtable->klass->has_finalize))
4909 mono_object_register_finalizer (o, error);
4915 * mono_object_new_fast:
4916 * @vtable: virtual table for the object.
4918 * This function allocates a new `MonoObject` with the type derived
4919 * from the @vtable information. The returned object is not tracked
4920 * for finalization. If your object implements a finalizer, you should
4921 * use `mono_object_new_alloc_specific` instead.
4923 * This method might raise an exception on errors. Use the
4924 * `mono_object_new_fast_checked` method if you want to manually raise
4927 * Returns: the allocated object.
4930 mono_object_new_fast (MonoVTable *vtable)
4933 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
4934 mono_error_raise_exception (&error);
4940 * mono_object_new_fast_checked:
4941 * @vtable: virtual table for the object.
4942 * @error: holds the error return value.
4944 * This function allocates a new `MonoObject` with the type derived
4945 * from the @vtable information. The returned object is not tracked
4946 * for finalization. If your object implements a finalizer, you should
4947 * use `mono_object_new_alloc_specific_checked` instead.
4949 * If there is not enough memory, the @error parameter will be set
4950 * and will contain a user-visible message with the amount of bytes
4951 * that were requested.
4953 * Returns: the allocated object, or NULL if there is not enough memory
4957 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
4959 MONO_REQ_GC_UNSAFE_MODE;
4963 mono_error_init (error);
4965 o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
4967 if (G_UNLIKELY (!o))
4968 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
4974 ves_icall_object_new_fast (MonoVTable *vtable)
4977 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
4978 mono_error_raise_exception (&error);
4984 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
4986 MONO_REQ_GC_UNSAFE_MODE;
4990 mono_error_init (error);
4992 o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
4994 if (G_UNLIKELY (!o))
4995 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
4996 else if (G_UNLIKELY (vtable->klass->has_finalize))
4997 mono_object_register_finalizer (o, error);
5003 * mono_class_get_allocation_ftn:
5005 * @for_box: the object will be used for boxing
5006 * @pass_size_in_words:
5008 * Return the allocation function appropriate for the given class.
5012 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
5014 MONO_REQ_GC_NEUTRAL_MODE;
5016 *pass_size_in_words = FALSE;
5018 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass) || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
5019 return ves_icall_object_new_specific;
5021 if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
5023 return ves_icall_object_new_fast;
5026 * FIXME: This is actually slower than ves_icall_object_new_fast, because
5027 * of the overhead of parameter passing.
5030 *pass_size_in_words = TRUE;
5031 #ifdef GC_REDIRECT_TO_LOCAL
5032 return GC_local_gcj_fast_malloc;
5034 return GC_gcj_fast_malloc;
5039 return ves_icall_object_new_specific;
5043 * mono_object_new_from_token:
5044 * @image: Context where the type_token is hosted
5045 * @token: a token of the type that we want to create
5047 * Returns: A newly created object whose definition is
5048 * looked up using @token in the @image image
5051 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
5053 MONO_REQ_GC_UNSAFE_MODE;
5059 klass = mono_class_get_checked (image, token, &error);
5060 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
5062 result = mono_object_new_checked (domain, klass, &error);
5064 mono_error_raise_exception (&error); /* FIXME don't raise here */
5071 * mono_object_clone:
5072 * @obj: the object to clone
5074 * Returns: A newly created object who is a shallow copy of @obj
5077 mono_object_clone (MonoObject *obj)
5080 MonoObject *o = mono_object_clone_checked (obj, &error);
5081 mono_error_raise_exception (&error);
5087 mono_object_clone_checked (MonoObject *obj, MonoError *error)
5089 MONO_REQ_GC_UNSAFE_MODE;
5094 mono_error_init (error);
5096 size = obj->vtable->klass->instance_size;
5098 if (obj->vtable->klass->rank)
5099 return (MonoObject*)mono_array_clone ((MonoArray*)obj);
5101 o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
5103 if (G_UNLIKELY (!o)) {
5104 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5108 /* If the object doesn't contain references this will do a simple memmove. */
5109 mono_gc_wbarrier_object_copy (o, obj);
5111 if (obj->vtable->klass->has_finalize)
5112 mono_object_register_finalizer (o, error);
5117 * mono_array_full_copy:
5118 * @src: source array to copy
5119 * @dest: destination array
5121 * Copies the content of one array to another with exactly the same type and size.
5124 mono_array_full_copy (MonoArray *src, MonoArray *dest)
5126 MONO_REQ_GC_UNSAFE_MODE;
5129 MonoClass *klass = src->obj.vtable->klass;
5131 g_assert (klass == dest->obj.vtable->klass);
5133 size = mono_array_length (src);
5134 g_assert (size == mono_array_length (dest));
5135 size *= mono_array_element_size (klass);
5137 if (klass->element_class->valuetype) {
5138 if (klass->element_class->has_references)
5139 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
5141 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5143 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
5146 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5151 * mono_array_clone_in_domain:
5152 * @domain: the domain in which the array will be cloned into
5153 * @array: the array to clone
5155 * This routine returns a copy of the array that is hosted on the
5156 * specified MonoDomain.
5159 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
5161 MONO_REQ_GC_UNSAFE_MODE;
5167 MonoClass *klass = array->obj.vtable->klass;
5169 if (array->bounds == NULL) {
5170 size = mono_array_length (array);
5171 o = mono_array_new_full_checked (domain, klass, &size, NULL, &error);
5172 mono_error_raise_exception (&error); /* FIXME don't raise here */
5174 size *= mono_array_element_size (klass);
5176 if (klass->element_class->valuetype) {
5177 if (klass->element_class->has_references)
5178 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5180 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5182 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5185 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5190 sizes = (uintptr_t *)alloca (klass->rank * sizeof(intptr_t) * 2);
5191 size = mono_array_element_size (klass);
5192 for (i = 0; i < klass->rank; ++i) {
5193 sizes [i] = array->bounds [i].length;
5194 size *= array->bounds [i].length;
5195 sizes [i + klass->rank] = array->bounds [i].lower_bound;
5197 o = mono_array_new_full_checked (domain, klass, sizes, (intptr_t*)sizes + klass->rank, &error);
5198 mono_error_raise_exception (&error); /* FIXME don't raise here */
5200 if (klass->element_class->valuetype) {
5201 if (klass->element_class->has_references)
5202 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5204 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5206 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5209 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5217 * @array: the array to clone
5219 * Returns: A newly created array who is a shallow copy of @array
5222 mono_array_clone (MonoArray *array)
5224 MONO_REQ_GC_UNSAFE_MODE;
5226 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
5229 /* helper macros to check for overflow when calculating the size of arrays */
5230 #ifdef MONO_BIG_ARRAYS
5231 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
5232 #define MYGUINT_MAX MYGUINT64_MAX
5233 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5234 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
5235 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5236 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
5237 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
5239 #define MYGUINT32_MAX 4294967295U
5240 #define MYGUINT_MAX MYGUINT32_MAX
5241 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5242 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
5243 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5244 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
5245 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
5249 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
5251 MONO_REQ_GC_NEUTRAL_MODE;
5255 byte_len = mono_array_element_size (klass);
5256 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
5259 if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
5261 byte_len += MONO_SIZEOF_MONO_ARRAY;
5269 * mono_array_new_full:
5270 * @domain: domain where the object is created
5271 * @array_class: array class
5272 * @lengths: lengths for each dimension in the array
5273 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
5275 * This routine creates a new array objects with the given dimensions,
5276 * lower bounds and type.
5279 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
5282 MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
5283 mono_error_raise_exception (&error);
5289 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
5291 MONO_REQ_GC_UNSAFE_MODE;
5293 uintptr_t byte_len = 0, len, bounds_size;
5296 MonoArrayBounds *bounds;
5300 mono_error_init (error);
5302 if (!array_class->inited)
5303 mono_class_init (array_class);
5307 /* A single dimensional array with a 0 lower bound is the same as an szarray */
5308 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
5310 if (len > MONO_ARRAY_MAX_INDEX) {
5311 mono_error_set_generic_error (error, "System", "OverflowException", "");
5316 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
5318 for (i = 0; i < array_class->rank; ++i) {
5319 if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
5320 mono_error_set_generic_error (error, "System", "OverflowException", "");
5323 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5324 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5331 if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5332 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5338 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5339 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5342 byte_len = (byte_len + 3) & ~3;
5343 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5344 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5347 byte_len += bounds_size;
5350 * Following three lines almost taken from mono_object_new ():
5351 * they need to be kept in sync.
5353 vtable = mono_class_vtable_full (domain, array_class, TRUE);
5355 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5357 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5359 if (G_UNLIKELY (!o)) {
5360 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", byte_len);
5364 array = (MonoArray*)o;
5366 bounds = array->bounds;
5369 for (i = 0; i < array_class->rank; ++i) {
5370 bounds [i].length = lengths [i];
5372 bounds [i].lower_bound = lower_bounds [i];
5381 * @domain: domain where the object is created
5382 * @eclass: element class
5383 * @n: number of array elements
5385 * This routine creates a new szarray with @n elements of type @eclass.
5388 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5390 MONO_REQ_GC_UNSAFE_MODE;
5396 ac = mono_array_class_get (eclass, 1);
5399 arr = mono_array_new_specific_checked (mono_class_vtable_full (domain, ac, TRUE), n, &error);
5400 mono_error_raise_exception (&error); /* FIXME don't raise here */
5406 * mono_array_new_specific:
5407 * @vtable: a vtable in the appropriate domain for an initialized class
5408 * @n: number of array elements
5410 * This routine is a fast alternative to mono_array_new() for code which
5411 * can be sure about the domain it operates in.
5414 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5417 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5418 mono_error_raise_exception (&error); /* FIXME don't raise here */
5424 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
5426 MONO_REQ_GC_UNSAFE_MODE;
5431 mono_error_init (error);
5433 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
5434 mono_error_set_generic_error (error, "System", "OverflowException", "");
5438 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
5439 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5442 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
5444 if (G_UNLIKELY (!o)) {
5445 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", byte_len);
5449 return (MonoArray*)o;
5453 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
5456 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5457 mono_error_raise_exception (&error);
5463 * mono_string_new_utf16:
5464 * @text: a pointer to an utf16 string
5465 * @len: the length of the string
5467 * Returns: A newly created string object which contains @text.
5470 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
5472 MONO_REQ_GC_UNSAFE_MODE;
5475 MonoString *res = NULL;
5476 res = mono_string_new_utf16_checked (domain, text, len, &error);
5477 mono_error_raise_exception (&error);
5483 * mono_string_new_utf16_checked:
5484 * @text: a pointer to an utf16 string
5485 * @len: the length of the string
5486 * @error: written on error.
5488 * Returns: A newly created string object which contains @text.
5489 * On error, returns NULL and sets @error.
5492 mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
5494 MONO_REQ_GC_UNSAFE_MODE;
5498 mono_error_init (error);
5500 s = mono_string_new_size_checked (domain, len, error);
5502 memcpy (mono_string_chars (s), text, len * 2);
5508 * mono_string_new_utf32:
5509 * @text: a pointer to an utf32 string
5510 * @len: the length of the string
5512 * Returns: A newly created string object which contains @text.
5515 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
5517 MONO_REQ_GC_UNSAFE_MODE;
5521 mono_unichar2 *utf16_output = NULL;
5522 gint32 utf16_len = 0;
5523 GError *gerror = NULL;
5524 glong items_written;
5526 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
5529 g_error_free (gerror);
5531 while (utf16_output [utf16_len]) utf16_len++;
5533 s = mono_string_new_size_checked (domain, utf16_len, &error);
5534 mono_error_raise_exception (&error); /* FIXME don't raise here */
5536 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
5538 g_free (utf16_output);
5544 * mono_string_new_size:
5545 * @text: a pointer to an utf16 string
5546 * @len: the length of the string
5548 * Returns: A newly created string object of @len
5551 mono_string_new_size (MonoDomain *domain, gint32 len)
5554 MonoString *str = mono_string_new_size_checked (domain, len, &error);
5555 mono_error_raise_exception (&error);
5561 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
5563 MONO_REQ_GC_UNSAFE_MODE;
5569 mono_error_init (error);
5571 /* check for overflow */
5572 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
5573 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
5577 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
5578 g_assert (size > 0);
5580 vtable = mono_class_vtable (domain, mono_defaults.string_class);
5583 s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
5585 if (G_UNLIKELY (!s)) {
5586 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5594 * mono_string_new_len:
5595 * @text: a pointer to an utf8 string
5596 * @length: number of bytes in @text to consider
5598 * Returns: A newly created string object which contains @text.
5601 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
5603 MONO_REQ_GC_UNSAFE_MODE;
5606 GError *eg_error = NULL;
5607 MonoString *o = NULL;
5609 glong items_written;
5611 mono_error_init (&error);
5613 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
5616 o = mono_string_new_utf16_checked (domain, ut, items_written, &error);
5618 g_error_free (eg_error);
5622 mono_error_raise_exception (&error); /* FIXME don't raise here */
5628 * @text: a pointer to an utf8 string
5630 * Returns: A newly created string object which contains @text.
5632 * This function asserts if it cannot allocate a new string.
5634 * @deprecated Use mono_string_new_checked in new code.
5637 mono_string_new (MonoDomain *domain, const char *text)
5640 MonoString *res = NULL;
5641 res = mono_string_new_checked (domain, text, &error);
5642 mono_error_assert_ok (&error);
5647 * mono_string_new_checked:
5648 * @text: a pointer to an utf8 string
5649 * @merror: set on error
5651 * Returns: A newly created string object which contains @text.
5652 * On error returns NULL and sets @merror.
5655 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
5657 MONO_REQ_GC_UNSAFE_MODE;
5659 GError *eg_error = NULL;
5660 MonoString *o = NULL;
5662 glong items_written;
5665 mono_error_init (error);
5669 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &eg_error);
5672 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
5674 g_error_free (eg_error);
5677 mono_error_raise_exception (error);
5679 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
5684 MonoString *o = NULL;
5686 if (!g_utf8_validate (text, -1, &end)) {
5687 mono_error_set_argument (error, "text", "Not a valid utf8 string");
5691 len = g_utf8_strlen (text, -1);
5692 o = mono_string_new_size_checked (domain, len, error);
5695 str = mono_string_chars (o);
5697 while (text < end) {
5698 *str++ = g_utf8_get_char (text);
5699 text = g_utf8_next_char (text);
5708 * mono_string_new_wrapper:
5709 * @text: pointer to utf8 characters.
5711 * Helper function to create a string object from @text in the current domain.
5714 mono_string_new_wrapper (const char *text)
5716 MONO_REQ_GC_UNSAFE_MODE;
5718 MonoDomain *domain = mono_domain_get ();
5721 return mono_string_new (domain, text);
5728 * @class: the class of the value
5729 * @value: a pointer to the unboxed data
5731 * Returns: A newly created object which contains @value.
5734 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
5736 MONO_REQ_GC_UNSAFE_MODE;
5743 g_assert (klass->valuetype);
5744 if (mono_class_is_nullable (klass))
5745 return mono_nullable_box ((guint8 *)value, klass);
5747 vtable = mono_class_vtable (domain, klass);
5750 size = mono_class_instance_size (klass);
5751 res = mono_object_new_alloc_specific_checked (vtable, &error);
5752 mono_error_raise_exception (&error); /* FIXME don't raise here */
5754 size = size - sizeof (MonoObject);
5757 g_assert (size == mono_class_value_size (klass, NULL));
5758 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
5760 #if NO_UNALIGNED_ACCESS
5761 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5765 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
5768 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
5771 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
5774 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
5777 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5781 if (klass->has_finalize) {
5782 mono_object_register_finalizer (res, &error);
5783 mono_error_raise_exception (&error); /* FIXME don't raise here */
5790 * @dest: destination pointer
5791 * @src: source pointer
5792 * @klass: a valuetype class
5794 * Copy a valuetype from @src to @dest. This function must be used
5795 * when @klass contains references fields.
5798 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
5800 MONO_REQ_GC_UNSAFE_MODE;
5802 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
5806 * mono_value_copy_array:
5807 * @dest: destination array
5808 * @dest_idx: index in the @dest array
5809 * @src: source pointer
5810 * @count: number of items
5812 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
5813 * This function must be used when @klass contains references fields.
5814 * Overlap is handled.
5817 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
5819 MONO_REQ_GC_UNSAFE_MODE;
5821 int size = mono_array_element_size (dest->obj.vtable->klass);
5822 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
5823 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
5824 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
5828 * mono_object_get_domain:
5829 * @obj: object to query
5831 * Returns: the MonoDomain where the object is hosted
5834 mono_object_get_domain (MonoObject *obj)
5836 MONO_REQ_GC_UNSAFE_MODE;
5838 return mono_object_domain (obj);
5842 * mono_object_get_class:
5843 * @obj: object to query
5845 * Use this function to obtain the `MonoClass*` for a given `MonoObject`.
5847 * Returns: the MonoClass of the object.
5850 mono_object_get_class (MonoObject *obj)
5852 MONO_REQ_GC_UNSAFE_MODE;
5854 return mono_object_class (obj);
5857 * mono_object_get_size:
5858 * @o: object to query
5860 * Returns: the size, in bytes, of @o
5863 mono_object_get_size (MonoObject* o)
5865 MONO_REQ_GC_UNSAFE_MODE;
5867 MonoClass* klass = mono_object_class (o);
5868 if (klass == mono_defaults.string_class) {
5869 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
5870 } else if (o->vtable->rank) {
5871 MonoArray *array = (MonoArray*)o;
5872 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
5873 if (array->bounds) {
5876 size += sizeof (MonoArrayBounds) * o->vtable->rank;
5880 return mono_class_instance_size (klass);
5885 * mono_object_unbox:
5886 * @obj: object to unbox
5888 * Returns: a pointer to the start of the valuetype boxed in this
5891 * This method will assert if the object passed is not a valuetype.
5894 mono_object_unbox (MonoObject *obj)
5896 MONO_REQ_GC_UNSAFE_MODE;
5898 /* add assert for valuetypes? */
5899 g_assert (obj->vtable->klass->valuetype);
5900 return ((char*)obj) + sizeof (MonoObject);
5904 * mono_object_isinst:
5906 * @klass: a pointer to a class
5908 * Returns: @obj if @obj is derived from @klass
5911 mono_object_isinst (MonoObject *obj, MonoClass *klass)
5913 MONO_REQ_GC_UNSAFE_MODE;
5916 mono_class_init (klass);
5918 if (mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
5919 return mono_object_isinst_mbyref (obj, klass);
5924 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
5928 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
5930 MONO_REQ_GC_UNSAFE_MODE;
5940 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5941 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
5945 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
5946 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
5949 MonoClass *oklass = vt->klass;
5950 if (mono_class_is_transparent_proxy (oklass))
5951 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
5953 mono_class_setup_supertypes (klass);
5954 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
5957 #ifndef DISABLE_REMOTING
5958 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
5960 MonoDomain *domain = mono_domain_get ();
5962 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
5963 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
5964 MonoMethod *im = NULL;
5967 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
5969 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
5970 im = mono_object_get_virtual_method (rp, im);
5973 pa [0] = mono_type_get_object_checked (domain, &klass->byval_arg, &error);
5974 mono_error_raise_exception (&error); /* FIXME don't raise here */
5977 res = mono_runtime_invoke_checked (im, rp, pa, &error);
5978 mono_error_raise_exception (&error); /* FIXME don't raise here */
5980 if (*(MonoBoolean *) mono_object_unbox(res)) {
5981 /* Update the vtable of the remote type, so it can safely cast to this new type */
5982 mono_upgrade_remote_class (domain, obj, klass);
5986 #endif /* DISABLE_REMOTING */
5991 * mono_object_castclass_mbyref:
5993 * @klass: a pointer to a class
5995 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
5998 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
6000 MONO_REQ_GC_UNSAFE_MODE;
6002 if (!obj) return NULL;
6003 if (mono_object_isinst_mbyref (obj, klass)) return obj;
6005 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
6007 "InvalidCastException"));
6012 MonoDomain *orig_domain;
6018 str_lookup (MonoDomain *domain, gpointer user_data)
6020 MONO_REQ_GC_UNSAFE_MODE;
6022 LDStrInfo *info = (LDStrInfo *)user_data;
6023 if (info->res || domain == info->orig_domain)
6025 info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
6029 mono_string_get_pinned (MonoString *str, MonoError *error)
6031 MONO_REQ_GC_UNSAFE_MODE;
6033 mono_error_init (error);
6035 /* We only need to make a pinned version of a string if this is a moving GC */
6036 if (!mono_gc_is_moving ())
6040 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
6041 news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
6043 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
6044 news->length = mono_string_length (str);
6046 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6052 mono_string_is_interned_lookup (MonoString *str, int insert)
6054 MONO_REQ_GC_UNSAFE_MODE;
6057 MonoGHashTable *ldstr_table;
6058 MonoString *s, *res;
6061 domain = ((MonoObject *)str)->vtable->domain;
6062 ldstr_table = domain->ldstr_table;
6064 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6070 /* Allocate outside the lock */
6072 s = mono_string_get_pinned (str, &error);
6073 mono_error_raise_exception (&error); /* FIXME don't raise here */
6076 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6081 mono_g_hash_table_insert (ldstr_table, s, s);
6086 LDStrInfo ldstr_info;
6087 ldstr_info.orig_domain = domain;
6088 ldstr_info.ins = str;
6089 ldstr_info.res = NULL;
6091 mono_domain_foreach (str_lookup, &ldstr_info);
6092 if (ldstr_info.res) {
6094 * the string was already interned in some other domain:
6095 * intern it in the current one as well.
6097 mono_g_hash_table_insert (ldstr_table, str, str);
6107 * mono_string_is_interned:
6108 * @o: String to probe
6110 * Returns whether the string has been interned.
6113 mono_string_is_interned (MonoString *o)
6115 MONO_REQ_GC_UNSAFE_MODE;
6117 return mono_string_is_interned_lookup (o, FALSE);
6121 * mono_string_intern:
6122 * @o: String to intern
6124 * Interns the string passed.
6125 * Returns: The interned string.
6128 mono_string_intern (MonoString *str)
6130 MONO_REQ_GC_UNSAFE_MODE;
6132 return mono_string_is_interned_lookup (str, TRUE);
6137 * @domain: the domain where the string will be used.
6138 * @image: a metadata context
6139 * @idx: index into the user string table.
6141 * Implementation for the ldstr opcode.
6142 * Returns: a loaded string from the @image/@idx combination.
6145 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
6147 MONO_REQ_GC_UNSAFE_MODE;
6149 if (image->dynamic) {
6150 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
6153 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6154 return NULL; /*FIXME we should probably be raising an exception here*/
6155 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
6160 * mono_ldstr_metadata_sig
6161 * @domain: the domain for the string
6162 * @sig: the signature of a metadata string
6164 * Returns: a MonoString for a string stored in the metadata
6167 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
6169 MONO_REQ_GC_UNSAFE_MODE;
6172 const char *str = sig;
6173 MonoString *o, *interned;
6176 len2 = mono_metadata_decode_blob_size (str, &str);
6179 o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, &error);
6180 mono_error_raise_exception (&error); /* FIXME don't raise here */
6181 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
6184 guint16 *p2 = (guint16*)mono_string_chars (o);
6185 for (i = 0; i < len2; ++i) {
6186 *p2 = GUINT16_FROM_LE (*p2);
6192 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6195 return interned; /* o will get garbage collected */
6197 o = mono_string_get_pinned (o, &error);
6198 mono_error_raise_exception (&error); /* FIXME don't raise here */
6201 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6203 mono_g_hash_table_insert (domain->ldstr_table, o, o);
6213 * mono_string_to_utf8:
6214 * @s: a System.String
6216 * Returns the UTF8 representation for @s.
6217 * The resulting buffer needs to be freed with mono_free().
6219 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
6222 mono_string_to_utf8 (MonoString *s)
6224 MONO_REQ_GC_UNSAFE_MODE;
6227 char *result = mono_string_to_utf8_checked (s, &error);
6229 if (!mono_error_ok (&error))
6230 mono_error_raise_exception (&error);
6235 * mono_string_to_utf8_checked:
6236 * @s: a System.String
6237 * @error: a MonoError.
6239 * Converts a MonoString to its UTF8 representation. May fail; check
6240 * @error to determine whether the conversion was successful.
6241 * The resulting buffer should be freed with mono_free().
6244 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
6246 MONO_REQ_GC_UNSAFE_MODE;
6250 GError *gerror = NULL;
6252 mono_error_init (error);
6258 return g_strdup ("");
6260 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
6262 mono_error_set_argument (error, "string", "%s", gerror->message);
6263 g_error_free (gerror);
6266 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6267 if (s->length > written) {
6268 /* allocate the total length and copy the part of the string that has been converted */
6269 char *as2 = (char *)g_malloc0 (s->length);
6270 memcpy (as2, as, written);
6279 * mono_string_to_utf8_ignore:
6282 * Converts a MonoString to its UTF8 representation. Will ignore
6283 * invalid surrogate pairs.
6284 * The resulting buffer should be freed with mono_free().
6288 mono_string_to_utf8_ignore (MonoString *s)
6290 MONO_REQ_GC_UNSAFE_MODE;
6299 return g_strdup ("");
6301 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
6303 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6304 if (s->length > written) {
6305 /* allocate the total length and copy the part of the string that has been converted */
6306 char *as2 = (char *)g_malloc0 (s->length);
6307 memcpy (as2, as, written);
6316 * mono_string_to_utf8_image_ignore:
6317 * @s: a System.String
6319 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
6322 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
6324 MONO_REQ_GC_UNSAFE_MODE;
6326 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
6330 * mono_string_to_utf8_mp_ignore:
6331 * @s: a System.String
6333 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
6336 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
6338 MONO_REQ_GC_UNSAFE_MODE;
6340 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
6345 * mono_string_to_utf16:
6348 * Return an null-terminated array of the utf-16 chars
6349 * contained in @s. The result must be freed with g_free().
6350 * This is a temporary helper until our string implementation
6351 * is reworked to always include the null terminating char.
6354 mono_string_to_utf16 (MonoString *s)
6356 MONO_REQ_GC_UNSAFE_MODE;
6363 as = (char *)g_malloc ((s->length * 2) + 2);
6364 as [(s->length * 2)] = '\0';
6365 as [(s->length * 2) + 1] = '\0';
6368 return (gunichar2 *)(as);
6371 memcpy (as, mono_string_chars(s), s->length * 2);
6372 return (gunichar2 *)(as);
6376 * mono_string_to_utf32:
6379 * Return an null-terminated array of the UTF-32 (UCS-4) chars
6380 * contained in @s. The result must be freed with g_free().
6383 mono_string_to_utf32 (MonoString *s)
6385 MONO_REQ_GC_UNSAFE_MODE;
6387 mono_unichar4 *utf32_output = NULL;
6388 GError *error = NULL;
6389 glong items_written;
6394 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
6397 g_error_free (error);
6399 return utf32_output;
6403 * mono_string_from_utf16:
6404 * @data: the UTF16 string (LPWSTR) to convert
6406 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
6408 * Returns: a MonoString.
6411 mono_string_from_utf16 (gunichar2 *data)
6413 MONO_REQ_GC_UNSAFE_MODE;
6416 MonoString *res = NULL;
6417 MonoDomain *domain = mono_domain_get ();
6423 while (data [len]) len++;
6425 res = mono_string_new_utf16_checked (domain, data, len, &error);
6426 mono_error_raise_exception (&error); /* FIXME don't raise here */
6431 * mono_string_from_utf32:
6432 * @data: the UTF32 string (LPWSTR) to convert
6434 * Converts a UTF32 (UCS-4)to a MonoString.
6436 * Returns: a MonoString.
6439 mono_string_from_utf32 (mono_unichar4 *data)
6441 MONO_REQ_GC_UNSAFE_MODE;
6443 MonoString* result = NULL;
6444 mono_unichar2 *utf16_output = NULL;
6445 GError *error = NULL;
6446 glong items_written;
6452 while (data [len]) len++;
6454 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &error);
6457 g_error_free (error);
6459 result = mono_string_from_utf16 (utf16_output);
6460 g_free (utf16_output);
6465 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
6467 MONO_REQ_GC_UNSAFE_MODE;
6474 r = mono_string_to_utf8_ignore (s);
6476 r = mono_string_to_utf8_checked (s, error);
6477 if (!mono_error_ok (error))
6484 len = strlen (r) + 1;
6486 mp_s = (char *)mono_mempool_alloc (mp, len);
6488 mp_s = (char *)mono_image_alloc (image, len);
6490 memcpy (mp_s, r, len);
6498 * mono_string_to_utf8_image:
6499 * @s: a System.String
6501 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
6504 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
6506 MONO_REQ_GC_UNSAFE_MODE;
6508 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
6512 * mono_string_to_utf8_mp:
6513 * @s: a System.String
6515 * Same as mono_string_to_utf8, but allocate the string from a mempool.
6518 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
6520 MONO_REQ_GC_UNSAFE_MODE;
6522 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
6526 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
6529 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
6531 eh_callbacks = *cbs;
6534 MonoRuntimeExceptionHandlingCallbacks *
6535 mono_get_eh_callbacks (void)
6537 return &eh_callbacks;
6541 * mono_raise_exception:
6542 * @ex: exception object
6544 * Signal the runtime that the exception @ex has been raised in unmanaged code.
6547 mono_raise_exception (MonoException *ex)
6549 MONO_REQ_GC_UNSAFE_MODE;
6552 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
6553 * that will cause gcc to omit the function epilog, causing problems when
6554 * the JIT tries to walk the stack, since the return address on the stack
6555 * will point into the next function in the executable, not this one.
6557 eh_callbacks.mono_raise_exception (ex);
6561 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
6563 MONO_REQ_GC_UNSAFE_MODE;
6565 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
6569 * mono_wait_handle_new:
6570 * @domain: Domain where the object will be created
6571 * @handle: Handle for the wait handle
6573 * Returns: A new MonoWaitHandle created in the given domain for the given handle
6576 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
6578 MONO_REQ_GC_UNSAFE_MODE;
6581 MonoWaitHandle *res;
6582 gpointer params [1];
6583 static MonoMethod *handle_set;
6585 res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, &error);
6586 mono_error_raise_exception (&error); /* FIXME don't raise here */
6588 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
6590 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
6592 params [0] = &handle;
6594 mono_runtime_invoke_checked (handle_set, res, params, &error);
6595 mono_error_raise_exception (&error); /* FIXME don't raise here */
6601 mono_wait_handle_get_handle (MonoWaitHandle *handle)
6603 MONO_REQ_GC_UNSAFE_MODE;
6605 static MonoClassField *f_safe_handle = NULL;
6608 if (!f_safe_handle) {
6609 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safeWaitHandle");
6610 g_assert (f_safe_handle);
6613 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
6619 mono_runtime_capture_context (MonoDomain *domain)
6621 MONO_REQ_GC_UNSAFE_MODE;
6623 RuntimeInvokeFunction runtime_invoke;
6625 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
6626 MonoMethod *method = mono_get_context_capture_method ();
6627 MonoMethod *wrapper;
6630 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
6631 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
6632 domain->capture_context_method = mono_compile_method (method);
6635 runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
6637 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
6640 * mono_async_result_new:
6641 * @domain:domain where the object will be created.
6642 * @handle: wait handle.
6643 * @state: state to pass to AsyncResult
6644 * @data: C closure data.
6646 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
6647 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
6651 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
6653 MONO_REQ_GC_UNSAFE_MODE;
6656 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, &error);
6657 mono_error_raise_exception (&error); /* FIXME don't raise here */
6658 MonoObject *context = mono_runtime_capture_context (domain);
6659 /* we must capture the execution context from the original thread */
6661 MONO_OBJECT_SETREF (res, execution_context, context);
6662 /* note: result may be null if the flow is suppressed */
6665 res->data = (void **)data;
6666 MONO_OBJECT_SETREF (res, object_data, object_data);
6667 MONO_OBJECT_SETREF (res, async_state, state);
6669 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
6671 res->sync_completed = FALSE;
6672 res->completed = FALSE;
6678 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
6680 MONO_REQ_GC_UNSAFE_MODE;
6687 g_assert (ares->async_delegate);
6689 ac = (MonoAsyncCall*) ares->object_data;
6691 res = mono_runtime_delegate_invoke (ares->async_delegate, (void**) &ares->async_state, NULL);
6693 gpointer wait_event = NULL;
6695 ac->msg->exc = NULL;
6696 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args);
6697 MONO_OBJECT_SETREF (ac, res, res);
6699 mono_monitor_enter ((MonoObject*) ares);
6700 ares->completed = 1;
6702 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
6703 mono_monitor_exit ((MonoObject*) ares);
6705 if (wait_event != NULL)
6706 SetEvent (wait_event);
6708 if (ac->cb_method) {
6709 mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
6710 mono_error_raise_exception (&error);
6718 mono_message_init (MonoDomain *domain,
6719 MonoMethodMessage *this_obj,
6720 MonoReflectionMethod *method,
6721 MonoArray *out_args)
6723 MONO_REQ_GC_UNSAFE_MODE;
6725 static MonoClass *object_array_klass;
6726 static MonoClass *byte_array_klass;
6727 static MonoClass *string_array_klass;
6729 MonoMethodSignature *sig = mono_method_signature (method->method);
6736 if (!object_array_klass) {
6739 klass = mono_array_class_get (mono_defaults.byte_class, 1);
6741 byte_array_klass = klass;
6743 klass = mono_array_class_get (mono_defaults.string_class, 1);
6745 string_array_klass = klass;
6747 klass = mono_array_class_get (mono_defaults.object_class, 1);
6750 mono_atomic_store_release (&object_array_klass, klass);
6753 MONO_OBJECT_SETREF (this_obj, method, method);
6755 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), sig->param_count, &error);
6756 mono_error_raise_exception (&error); /* FIXME don't raise here */
6758 MONO_OBJECT_SETREF (this_obj, args, arr);
6760 arr = mono_array_new_specific_checked (mono_class_vtable (domain, byte_array_klass), sig->param_count, &error);
6761 mono_error_raise_exception (&error); /* FIXME don't raise here */
6763 MONO_OBJECT_SETREF (this_obj, arg_types, arr);
6765 this_obj->async_result = NULL;
6766 this_obj->call_type = CallType_Sync;
6768 names = g_new (char *, sig->param_count);
6769 mono_method_get_param_names (method->method, (const char **) names);
6771 arr = mono_array_new_specific_checked (mono_class_vtable (domain, string_array_klass), sig->param_count, &error);
6772 mono_error_raise_exception (&error); /* FIXME don't raise here */
6774 MONO_OBJECT_SETREF (this_obj, names, arr);
6776 for (i = 0; i < sig->param_count; i++) {
6777 name = mono_string_new (domain, names [i]);
6778 mono_array_setref (this_obj->names, i, name);
6782 for (i = 0, j = 0; i < sig->param_count; i++) {
6783 if (sig->params [i]->byref) {
6785 MonoObject* arg = (MonoObject *)mono_array_get (out_args, gpointer, j);
6786 mono_array_setref (this_obj->args, i, arg);
6790 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
6794 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
6797 mono_array_set (this_obj->arg_types, guint8, i, arg_type);
6801 #ifndef DISABLE_REMOTING
6803 * mono_remoting_invoke:
6804 * @real_proxy: pointer to a RealProxy object
6805 * @msg: The MonoMethodMessage to execute
6806 * @exc: used to store exceptions
6807 * @out_args: used to store output arguments
6809 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
6810 * IMessage interface and it is not trivial to extract results from there. So
6811 * we call an helper method PrivateInvoke instead of calling
6812 * RealProxy::Invoke() directly.
6814 * Returns: the result object.
6817 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
6818 MonoObject **exc, MonoArray **out_args)
6820 MONO_REQ_GC_UNSAFE_MODE;
6824 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
6827 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
6830 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
6832 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6833 real_proxy->vtable->domain->private_invoke_method = im;
6836 pa [0] = real_proxy;
6842 o = mono_runtime_try_invoke (im, NULL, pa, exc, &error);
6844 o = mono_runtime_invoke_checked (im, NULL, pa, &error);
6846 mono_error_raise_exception (&error); /* FIXME don't raise here */
6853 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
6854 MonoObject **exc, MonoArray **out_args)
6856 MONO_REQ_GC_UNSAFE_MODE;
6858 static MonoClass *object_array_klass;
6862 MonoMethodSignature *sig;
6865 int i, j, outarg_count = 0;
6867 #ifndef DISABLE_REMOTING
6868 if (target && mono_object_is_transparent_proxy (target)) {
6869 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
6870 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6871 target = tp->rp->unwrapped_server;
6873 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
6878 domain = mono_domain_get ();
6879 method = msg->method->method;
6880 sig = mono_method_signature (method);
6882 for (i = 0; i < sig->param_count; i++) {
6883 if (sig->params [i]->byref)
6887 if (!object_array_klass) {
6890 klass = mono_array_class_get (mono_defaults.object_class, 1);
6893 mono_memory_barrier ();
6894 object_array_klass = klass;
6897 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, &error);
6898 mono_error_raise_exception (&error); /* FIXME don't raise here */
6900 mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
6903 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
6905 for (i = 0, j = 0; i < sig->param_count; i++) {
6906 if (sig->params [i]->byref) {
6908 arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
6909 mono_array_setref (*out_args, j, arg);
6918 * mono_object_to_string:
6920 * @exc: Any exception thrown by ToString (). May be NULL.
6922 * Returns: the result of calling ToString () on an object.
6925 mono_object_to_string (MonoObject *obj, MonoObject **exc)
6927 MONO_REQ_GC_UNSAFE_MODE;
6929 static MonoMethod *to_string = NULL;
6938 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
6940 method = mono_object_get_virtual_method (obj, to_string);
6942 // Unbox value type if needed
6943 if (mono_class_is_valuetype (mono_method_get_class (method))) {
6944 target = mono_object_unbox (obj);
6948 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
6949 if (*exc == NULL && !mono_error_ok (&error))
6950 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
6952 mono_error_cleanup (&error);
6954 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
6955 mono_error_raise_exception (&error); /* FIXME don't raise here */
6962 * mono_print_unhandled_exception:
6963 * @exc: The exception
6965 * Prints the unhandled exception.
6968 mono_print_unhandled_exception (MonoObject *exc)
6970 MONO_REQ_GC_UNSAFE_MODE;
6973 char *message = (char*)"";
6974 gboolean free_message = FALSE;
6977 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
6978 message = g_strdup ("OutOfMemoryException");
6979 free_message = TRUE;
6980 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
6981 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
6982 free_message = TRUE;
6985 if (((MonoException*)exc)->native_trace_ips) {
6986 message = mono_exception_get_native_backtrace ((MonoException*)exc);
6987 free_message = TRUE;
6989 MonoObject *other_exc = NULL;
6990 str = mono_object_to_string (exc, &other_exc);
6992 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
6993 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
6995 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
6996 original_backtrace, nested_backtrace);
6998 g_free (original_backtrace);
6999 g_free (nested_backtrace);
7000 free_message = TRUE;
7002 message = mono_string_to_utf8_checked (str, &error);
7003 if (!mono_error_ok (&error)) {
7004 mono_error_cleanup (&error);
7005 message = (char *) "";
7007 free_message = TRUE;
7014 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
7015 * exc->vtable->klass->name, message);
7017 g_printerr ("\nUnhandled Exception:\n%s\n", message);
7024 * mono_delegate_ctor:
7025 * @this: pointer to an uninitialized delegate object
7026 * @target: target object
7027 * @addr: pointer to native code
7030 * Initialize a delegate and sets a specific method, not the one
7031 * associated with addr. This is useful when sharing generic code.
7032 * In that case addr will most probably not be associated with the
7033 * correct instantiation of the method.
7036 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method)
7038 MONO_REQ_GC_UNSAFE_MODE;
7040 MonoDelegate *delegate = (MonoDelegate *)this_obj;
7042 g_assert (this_obj);
7045 g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
7048 delegate->method = method;
7050 mono_stats.delegate_creations++;
7052 #ifndef DISABLE_REMOTING
7053 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
7055 method = mono_marshal_get_remoting_invoke (method);
7056 delegate->method_ptr = mono_compile_method (method);
7057 MONO_OBJECT_SETREF (delegate, target, target);
7061 delegate->method_ptr = addr;
7062 MONO_OBJECT_SETREF (delegate, target, target);
7065 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
7066 if (callbacks.init_delegate)
7067 callbacks.init_delegate (delegate);
7071 * mono_delegate_ctor:
7072 * @this: pointer to an uninitialized delegate object
7073 * @target: target object
7074 * @addr: pointer to native code
7076 * This is used to initialize a delegate.
7079 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr)
7081 MONO_REQ_GC_UNSAFE_MODE;
7083 MonoDomain *domain = mono_domain_get ();
7085 MonoMethod *method = NULL;
7089 ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
7091 if (!ji && domain != mono_get_root_domain ())
7092 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
7094 method = mono_jit_info_get_method (ji);
7095 g_assert (!method->klass->generic_container);
7098 mono_delegate_ctor_with_method (this_obj, target, addr, method);
7102 * mono_method_call_message_new:
7103 * @method: method to encapsulate
7104 * @params: parameters to the method
7105 * @invoke: optional, delegate invoke.
7106 * @cb: async callback delegate.
7107 * @state: state passed to the async callback.
7109 * Translates arguments pointers into a MonoMethodMessage.
7112 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
7113 MonoDelegate **cb, MonoObject **state)
7115 MONO_REQ_GC_UNSAFE_MODE;
7119 MonoDomain *domain = mono_domain_get ();
7120 MonoMethodSignature *sig = mono_method_signature (method);
7121 MonoMethodMessage *msg;
7124 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7125 mono_error_raise_exception (&error); /* FIXME don't raise here */
7128 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, &error);
7129 mono_error_raise_exception (&error); /* FIXME don't raise here */
7130 mono_message_init (domain, msg, rm, NULL);
7131 count = sig->param_count - 2;
7133 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, &error);
7134 mono_error_raise_exception (&error); /* FIXME don't raise here */
7135 mono_message_init (domain, msg, rm, NULL);
7136 count = sig->param_count;
7139 for (i = 0; i < count; i++) {
7144 if (sig->params [i]->byref)
7145 vpos = *((gpointer *)params [i]);
7149 klass = mono_class_from_mono_type (sig->params [i]);
7151 if (klass->valuetype)
7152 arg = mono_value_box (domain, klass, vpos);
7154 arg = *((MonoObject **)vpos);
7156 mono_array_setref (msg->args, i, arg);
7159 if (cb != NULL && state != NULL) {
7160 *cb = *((MonoDelegate **)params [i]);
7162 *state = *((MonoObject **)params [i]);
7169 * mono_method_return_message_restore:
7171 * Restore results from message based processing back to arguments pointers
7174 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
7176 MONO_REQ_GC_UNSAFE_MODE;
7178 MonoMethodSignature *sig = mono_method_signature (method);
7179 int i, j, type, size, out_len;
7181 if (out_args == NULL)
7183 out_len = mono_array_length (out_args);
7187 for (i = 0, j = 0; i < sig->param_count; i++) {
7188 MonoType *pt = sig->params [i];
7193 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
7195 arg = (char *)mono_array_get (out_args, gpointer, j);
7198 g_assert (type != MONO_TYPE_VOID);
7200 if (MONO_TYPE_IS_REFERENCE (pt)) {
7201 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
7204 MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
7205 size = mono_class_value_size (klass, NULL);
7206 if (klass->has_references)
7207 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
7209 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
7211 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
7212 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
7221 #ifndef DISABLE_REMOTING
7224 * mono_load_remote_field:
7225 * @this: pointer to an object
7226 * @klass: klass of the object containing @field
7227 * @field: the field to load
7228 * @res: a storage to store the result
7230 * This method is called by the runtime on attempts to load fields of
7231 * transparent proxy objects. @this points to such TP, @klass is the class of
7232 * the object containing @field. @res is a storage location which can be
7233 * used to store the result.
7235 * Returns: an address pointing to the value of field.
7238 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
7240 MONO_REQ_GC_UNSAFE_MODE;
7244 static MonoMethod *getter = NULL;
7245 MonoDomain *domain = mono_domain_get ();
7246 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7247 MonoClass *field_class;
7248 MonoMethodMessage *msg;
7249 MonoArray *out_args;
7253 g_assert (mono_object_is_transparent_proxy (this_obj));
7254 g_assert (res != NULL);
7256 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7257 mono_field_get_value (tp->rp->unwrapped_server, field, res);
7262 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
7264 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7267 field_class = mono_class_from_mono_type (field->type);
7269 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7270 mono_error_raise_exception (&error); /* FIXME don't raise here */
7271 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
7272 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, &error);
7273 mono_error_raise_exception (&error); /* FIXME don't raise here */
7274 mono_message_init (domain, msg, rm, out_args);
7276 full_name = mono_type_get_full_name (klass);
7277 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7278 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7281 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
7283 if (exc) mono_raise_exception ((MonoException *)exc);
7285 if (mono_array_length (out_args) == 0)
7288 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
7290 if (field_class->valuetype) {
7291 return ((char *)*res) + sizeof (MonoObject);
7297 * mono_load_remote_field_new:
7302 * Missing documentation.
7305 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
7307 MONO_REQ_GC_UNSAFE_MODE;
7311 static MonoMethod *getter = NULL;
7312 MonoDomain *domain = mono_domain_get ();
7313 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7314 MonoClass *field_class;
7315 MonoMethodMessage *msg;
7316 MonoArray *out_args;
7317 MonoObject *exc, *res;
7320 g_assert (mono_object_is_transparent_proxy (this_obj));
7322 field_class = mono_class_from_mono_type (field->type);
7324 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7326 if (field_class->valuetype) {
7327 res = mono_object_new_checked (domain, field_class, &error);
7328 mono_error_raise_exception (&error); /* FIXME don't raise here */
7329 val = ((gchar *) res) + sizeof (MonoObject);
7333 mono_field_get_value (tp->rp->unwrapped_server, field, val);
7338 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
7340 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7343 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7344 mono_error_raise_exception (&error); /* FIXME don't raise here */
7345 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
7347 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, &error);
7348 mono_error_raise_exception (&error); /* FIXME don't raise here */
7349 mono_message_init (domain, msg, rm, out_args);
7351 full_name = mono_type_get_full_name (klass);
7352 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7353 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7356 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
7358 if (exc) mono_raise_exception ((MonoException *)exc);
7360 if (mono_array_length (out_args) == 0)
7363 res = mono_array_get (out_args, MonoObject *, 0);
7369 * mono_store_remote_field:
7370 * @this_obj: pointer to an object
7371 * @klass: klass of the object containing @field
7372 * @field: the field to load
7373 * @val: the value/object to store
7375 * This method is called by the runtime on attempts to store fields of
7376 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
7377 * the object containing @field. @val is the new value to store in @field.
7380 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
7382 MONO_REQ_GC_UNSAFE_MODE;
7386 static MonoMethod *setter = NULL;
7387 MonoDomain *domain = mono_domain_get ();
7388 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7389 MonoClass *field_class;
7390 MonoMethodMessage *msg;
7391 MonoArray *out_args;
7396 g_assert (mono_object_is_transparent_proxy (this_obj));
7398 field_class = mono_class_from_mono_type (field->type);
7400 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7401 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
7402 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
7407 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
7409 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7412 if (field_class->valuetype)
7413 arg = mono_value_box (domain, field_class, val);
7415 arg = *((MonoObject **)val);
7418 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7419 mono_error_raise_exception (&error); /* FIXME don't raise here */
7420 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, setter, NULL, &error);
7421 mono_error_raise_exception (&error); /* FIXME don't raise here */
7422 mono_message_init (domain, msg, rm, NULL);
7424 full_name = mono_type_get_full_name (klass);
7425 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7426 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7427 mono_array_setref (msg->args, 2, arg);
7430 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
7432 if (exc) mono_raise_exception ((MonoException *)exc);
7436 * mono_store_remote_field_new:
7442 * Missing documentation
7445 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
7447 MONO_REQ_GC_UNSAFE_MODE;
7451 static MonoMethod *setter = NULL;
7452 MonoDomain *domain = mono_domain_get ();
7453 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7454 MonoClass *field_class;
7455 MonoMethodMessage *msg;
7456 MonoArray *out_args;
7460 g_assert (mono_object_is_transparent_proxy (this_obj));
7462 field_class = mono_class_from_mono_type (field->type);
7464 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7465 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
7466 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
7471 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
7473 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7476 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7477 mono_error_raise_exception (&error); /* FIXME don't raise here */
7478 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, setter, NULL, &error);
7479 mono_error_raise_exception (&error); /* FIXME don't raise here */
7480 mono_message_init (domain, msg, rm, NULL);
7482 full_name = mono_type_get_full_name (klass);
7483 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7484 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7485 mono_array_setref (msg->args, 2, arg);
7488 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
7490 if (exc) mono_raise_exception ((MonoException *)exc);
7495 * mono_create_ftnptr:
7497 * Given a function address, create a function descriptor for it.
7498 * This is only needed on some platforms.
7501 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
7503 return callbacks.create_ftnptr (domain, addr);
7507 * mono_get_addr_from_ftnptr:
7509 * Given a pointer to a function descriptor, return the function address.
7510 * This is only needed on some platforms.
7513 mono_get_addr_from_ftnptr (gpointer descr)
7515 return callbacks.get_addr_from_ftnptr (descr);
7519 * mono_string_chars:
7522 * Returns a pointer to the UCS16 characters stored in the MonoString
7525 mono_string_chars (MonoString *s)
7527 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
7533 * mono_string_length:
7536 * Returns the lenght in characters of the string
7539 mono_string_length (MonoString *s)
7541 MONO_REQ_GC_UNSAFE_MODE;
7547 * mono_array_length:
7548 * @array: a MonoArray*
7550 * Returns the total number of elements in the array. This works for
7551 * both vectors and multidimensional arrays.
7554 mono_array_length (MonoArray *array)
7556 MONO_REQ_GC_UNSAFE_MODE;
7558 return array->max_length;
7562 * mono_array_addr_with_size:
7563 * @array: a MonoArray*
7564 * @size: size of the array elements
7565 * @idx: index into the array
7567 * Use this function to obtain the address for the @idx item on the
7568 * @array containing elements of size @size.
7570 * This method performs no bounds checking or type checking.
7572 * Returns the address of the @idx element in the array.
7575 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
7577 MONO_REQ_GC_UNSAFE_MODE;
7579 return ((char*)(array)->vector) + size * idx;
7584 mono_glist_to_array (GList *list, MonoClass *eclass)
7586 MonoDomain *domain = mono_domain_get ();
7593 len = g_list_length (list);
7594 res = mono_array_new (domain, eclass, len);
7596 for (i = 0; list; list = list->next, i++)
7597 mono_array_set (res, gpointer, i, list->data);
7604 * The following section is purely to declare prototypes and
7605 * document the API, as these C files are processed by our
7611 * @array: array to alter
7612 * @element_type: A C type name, this macro will use the sizeof(type) to determine the element size
7613 * @index: index into the array
7614 * @value: value to set
7616 * Value Type version: This sets the @index's element of the @array
7617 * with elements of size sizeof(type) to the provided @value.
7619 * This macro does not attempt to perform type checking or bounds checking.
7621 * Use this to set value types in a `MonoArray`.
7623 void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
7628 * mono_array_setref:
7629 * @array: array to alter
7630 * @index: index into the array
7631 * @value: value to set
7633 * Reference Type version: This sets the @index's element of the
7634 * @array with elements of size sizeof(type) to the provided @value.
7636 * This macro does not attempt to perform type checking or bounds checking.
7638 * Use this to reference types in a `MonoArray`.
7640 void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
7646 * @array: array on which to operate on
7647 * @element_type: C element type (example: MonoString *, int, MonoObject *)
7648 * @index: index into the array
7650 * Use this macro to retrieve the @index element of an @array and
7651 * extract the value assuming that the elements of the array match
7652 * the provided type value.
7654 * This method can be used with both arrays holding value types and
7655 * reference types. For reference types, the @type parameter should
7656 * be a `MonoObject*` or any subclass of it, like `MonoString*`.
7658 * This macro does not attempt to perform type checking or bounds checking.
7660 * Returns: The element at the @index position in the @array.
7662 Type mono_array_get (MonoArray *array, Type element_type, uintptr_t index)