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;
1050 MonoCustomAttrInfo *ainfo;
1052 ainfo = mono_custom_attrs_from_field_checked (fklass, field, &error);
1053 mono_error_cleanup (&error); /* FIXME don't swallow the error? */
1056 for (i = 0; i < ainfo->num_attrs; ++i) {
1057 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1058 if (klass->image == mono_defaults.corlib) {
1059 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1060 mono_custom_attrs_free (ainfo);
1061 return SPECIAL_STATIC_THREAD;
1063 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1064 mono_custom_attrs_free (ainfo);
1065 return SPECIAL_STATIC_CONTEXT;
1069 mono_custom_attrs_free (ainfo);
1070 return SPECIAL_STATIC_NONE;
1073 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1074 #define mix(a,b,c) { \
1075 a -= c; a ^= rot(c, 4); c += b; \
1076 b -= a; b ^= rot(a, 6); a += c; \
1077 c -= b; c ^= rot(b, 8); b += a; \
1078 a -= c; a ^= rot(c,16); c += b; \
1079 b -= a; b ^= rot(a,19); a += c; \
1080 c -= b; c ^= rot(b, 4); b += a; \
1082 #define final(a,b,c) { \
1083 c ^= b; c -= rot(b,14); \
1084 a ^= c; a -= rot(c,11); \
1085 b ^= a; b -= rot(a,25); \
1086 c ^= b; c -= rot(b,16); \
1087 a ^= c; a -= rot(c,4); \
1088 b ^= a; b -= rot(a,14); \
1089 c ^= b; c -= rot(b,24); \
1093 * mono_method_get_imt_slot:
1095 * The IMT slot is embedded into AOTed code, so this must return the same value
1096 * for the same method across all executions. This means:
1097 * - pointers shouldn't be used as hash values.
1098 * - mono_metadata_str_hash () should be used for hashing strings.
1101 mono_method_get_imt_slot (MonoMethod *method)
1103 MONO_REQ_GC_NEUTRAL_MODE;
1105 MonoMethodSignature *sig;
1107 guint32 *hashes_start, *hashes;
1111 /* This can be used to stress tests the collision code */
1115 * We do this to simplify generic sharing. It will hurt
1116 * performance in cases where a class implements two different
1117 * instantiations of the same generic interface.
1118 * The code in build_imt_slots () depends on this.
1120 if (method->is_inflated)
1121 method = ((MonoMethodInflated*)method)->declaring;
1123 sig = mono_method_signature (method);
1124 hashes_count = sig->param_count + 4;
1125 hashes_start = (guint32 *)malloc (hashes_count * sizeof (guint32));
1126 hashes = hashes_start;
1128 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1129 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1130 method->klass->name_space, method->klass->name, method->name);
1133 /* Initialize hashes */
1134 hashes [0] = mono_metadata_str_hash (method->klass->name);
1135 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1136 hashes [2] = mono_metadata_str_hash (method->name);
1137 hashes [3] = mono_metadata_type_hash (sig->ret);
1138 for (i = 0; i < sig->param_count; i++) {
1139 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1142 /* Setup internal state */
1143 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1145 /* Handle most of the hashes */
1146 while (hashes_count > 3) {
1155 /* Handle the last 3 hashes (all the case statements fall through) */
1156 switch (hashes_count) {
1157 case 3 : c += hashes [2];
1158 case 2 : b += hashes [1];
1159 case 1 : a += hashes [0];
1161 case 0: /* nothing left to add */
1165 free (hashes_start);
1166 /* Report the result */
1167 return c % MONO_IMT_SIZE;
1176 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1177 MONO_REQ_GC_NEUTRAL_MODE;
1179 guint32 imt_slot = mono_method_get_imt_slot (method);
1180 MonoImtBuilderEntry *entry;
1182 if (slot_num >= 0 && imt_slot != slot_num) {
1183 /* we build just a single imt slot and this is not it */
1187 entry = (MonoImtBuilderEntry *)g_malloc0 (sizeof (MonoImtBuilderEntry));
1188 entry->key = method;
1189 entry->value.vtable_slot = vtable_slot;
1190 entry->next = imt_builder [imt_slot];
1191 if (imt_builder [imt_slot] != NULL) {
1192 entry->children = imt_builder [imt_slot]->children + 1;
1193 if (entry->children == 1) {
1194 mono_stats.imt_slots_with_collisions++;
1195 *imt_collisions_bitmap |= (1 << imt_slot);
1198 entry->children = 0;
1199 mono_stats.imt_used_slots++;
1201 imt_builder [imt_slot] = entry;
1204 char *method_name = mono_method_full_name (method, TRUE);
1205 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1206 method, method_name, imt_slot, vtable_slot, entry->children);
1207 g_free (method_name);
1214 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1216 MonoMethod *method = e->key;
1217 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1221 method->klass->name_space,
1222 method->klass->name,
1225 printf (" * %s: NULL\n", message);
1231 compare_imt_builder_entries (const void *p1, const void *p2) {
1232 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1233 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1235 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1239 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1241 MONO_REQ_GC_NEUTRAL_MODE;
1243 int count = end - start;
1244 int chunk_start = out_array->len;
1247 for (i = start; i < end; ++i) {
1248 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1249 item->key = sorted_array [i]->key;
1250 item->value = sorted_array [i]->value;
1251 item->has_target_code = sorted_array [i]->has_target_code;
1252 item->is_equals = TRUE;
1254 item->check_target_idx = out_array->len + 1;
1256 item->check_target_idx = 0;
1257 g_ptr_array_add (out_array, item);
1260 int middle = start + count / 2;
1261 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1263 item->key = sorted_array [middle]->key;
1264 item->is_equals = FALSE;
1265 g_ptr_array_add (out_array, item);
1266 imt_emit_ir (sorted_array, start, middle, out_array);
1267 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1273 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1274 MONO_REQ_GC_NEUTRAL_MODE;
1276 int number_of_entries = entries->children + 1;
1277 MonoImtBuilderEntry **sorted_array = (MonoImtBuilderEntry **)malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1278 GPtrArray *result = g_ptr_array_new ();
1279 MonoImtBuilderEntry *current_entry;
1282 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1283 sorted_array [i] = current_entry;
1285 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1287 /*for (i = 0; i < number_of_entries; i++) {
1288 print_imt_entry (" sorted array:", sorted_array [i], i);
1291 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1293 free (sorted_array);
1298 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1300 MONO_REQ_GC_NEUTRAL_MODE;
1302 if (imt_builder_entry != NULL) {
1303 if (imt_builder_entry->children == 0 && !fail_tramp && !always_build_imt_thunks) {
1304 /* No collision, return the vtable slot contents */
1305 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1307 /* Collision, build the thunk */
1308 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1311 result = imt_thunk_builder (vtable, domain,
1312 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1313 for (i = 0; i < imt_ir->len; ++i)
1314 g_free (g_ptr_array_index (imt_ir, i));
1315 g_ptr_array_free (imt_ir, TRUE);
1327 static MonoImtBuilderEntry*
1328 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1331 * LOCKING: requires the loader and domain locks.
1335 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1337 MONO_REQ_GC_NEUTRAL_MODE;
1341 guint32 imt_collisions_bitmap = 0;
1342 MonoImtBuilderEntry **imt_builder = (MonoImtBuilderEntry **)calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1343 int method_count = 0;
1344 gboolean record_method_count_for_max_collisions = FALSE;
1345 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1348 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1350 for (i = 0; i < klass->interface_offsets_count; ++i) {
1351 MonoClass *iface = klass->interfaces_packed [i];
1352 int interface_offset = klass->interface_offsets_packed [i];
1353 int method_slot_in_interface, vt_slot;
1355 if (mono_class_has_variant_generic_params (iface))
1356 has_variant_iface = TRUE;
1358 mono_class_setup_methods (iface);
1359 vt_slot = interface_offset;
1360 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1363 if (slot_num >= 0 && iface->is_inflated) {
1365 * The imt slot of the method is the same as for its declaring method,
1366 * see the comment in mono_method_get_imt_slot (), so we can
1367 * avoid inflating methods which will be discarded by
1368 * add_imt_builder_entry anyway.
1370 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1371 if (mono_method_get_imt_slot (method) != slot_num) {
1376 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1377 if (method->is_generic) {
1378 has_generic_virtual = TRUE;
1383 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1384 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1389 if (extra_interfaces) {
1390 int interface_offset = klass->vtable_size;
1392 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1393 MonoClass* iface = (MonoClass *)list_item->data;
1394 int method_slot_in_interface;
1395 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1396 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1398 if (method->is_generic)
1399 has_generic_virtual = TRUE;
1400 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1402 interface_offset += iface->method.count;
1405 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1406 /* overwrite the imt slot only if we're building all the entries or if
1407 * we're building this specific one
1409 if (slot_num < 0 || i == slot_num) {
1410 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1413 if (imt_builder [i]) {
1414 MonoImtBuilderEntry *entry;
1416 /* Link entries with imt_builder [i] */
1417 for (entry = entries; entry->next; entry = entry->next) {
1419 MonoMethod *method = (MonoMethod*)entry->key;
1420 char *method_name = mono_method_full_name (method, TRUE);
1421 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1422 g_free (method_name);
1425 entry->next = imt_builder [i];
1426 entries->children += imt_builder [i]->children + 1;
1428 imt_builder [i] = entries;
1431 if (has_generic_virtual || has_variant_iface) {
1433 * There might be collisions later when the the thunk is expanded.
1435 imt_collisions_bitmap |= (1 << i);
1438 * The IMT thunk might be called with an instance of one of the
1439 * generic virtual methods, so has to fallback to the IMT trampoline.
1441 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline (vt, i));
1443 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1446 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1450 if (imt_builder [i] != NULL) {
1451 int methods_in_slot = imt_builder [i]->children + 1;
1452 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1453 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1454 record_method_count_for_max_collisions = TRUE;
1456 method_count += methods_in_slot;
1460 mono_stats.imt_number_of_methods += method_count;
1461 if (record_method_count_for_max_collisions) {
1462 mono_stats.imt_method_count_when_max_collisions = method_count;
1465 for (i = 0; i < MONO_IMT_SIZE; i++) {
1466 MonoImtBuilderEntry* entry = imt_builder [i];
1467 while (entry != NULL) {
1468 MonoImtBuilderEntry* next = entry->next;
1474 /* we OR the bitmap since we may build just a single imt slot at a time */
1475 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1479 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1480 MONO_REQ_GC_NEUTRAL_MODE;
1482 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1486 * mono_vtable_build_imt_slot:
1487 * @vtable: virtual object table struct
1488 * @imt_slot: slot in the IMT table
1490 * Fill the given @imt_slot in the IMT table of @vtable with
1491 * a trampoline or a thunk for the case of collisions.
1492 * This is part of the internal mono API.
1494 * LOCKING: Take the domain lock.
1497 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1499 MONO_REQ_GC_NEUTRAL_MODE;
1501 gpointer *imt = (gpointer*)vtable;
1502 imt -= MONO_IMT_SIZE;
1503 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1505 /* no support for extra interfaces: the proxy objects will need
1506 * to build the complete IMT
1507 * Update and heck needs to ahppen inside the proper domain lock, as all
1508 * the changes made to a MonoVTable.
1510 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1511 mono_domain_lock (vtable->domain);
1512 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1513 if (!callbacks.imt_entry_inited (vtable, imt_slot))
1514 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1515 mono_domain_unlock (vtable->domain);
1516 mono_loader_unlock ();
1521 * The first two free list entries both belong to the wait list: The
1522 * first entry is the pointer to the head of the list and the second
1523 * entry points to the last element. That way appending and removing
1524 * the first element are both O(1) operations.
1526 #ifdef MONO_SMALL_CONFIG
1527 #define NUM_FREE_LISTS 6
1529 #define NUM_FREE_LISTS 12
1531 #define FIRST_FREE_LIST_SIZE 64
1532 #define MAX_WAIT_LENGTH 50
1533 #define THUNK_THRESHOLD 10
1536 * LOCKING: The domain lock must be held.
1539 init_thunk_free_lists (MonoDomain *domain)
1541 MONO_REQ_GC_NEUTRAL_MODE;
1543 if (domain->thunk_free_lists)
1545 domain->thunk_free_lists = (MonoThunkFreeList **)mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1549 list_index_for_size (int item_size)
1552 int size = FIRST_FREE_LIST_SIZE;
1554 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1563 * mono_method_alloc_generic_virtual_thunk:
1565 * @size: size in bytes
1567 * Allocs size bytes to be used for the code of a generic virtual
1568 * thunk. It's either allocated from the domain's code manager or
1569 * reused from a previously invalidated piece.
1571 * LOCKING: The domain lock must be held.
1574 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1576 MONO_REQ_GC_NEUTRAL_MODE;
1578 static gboolean inited = FALSE;
1579 static int generic_virtual_thunks_size = 0;
1583 MonoThunkFreeList **l;
1585 init_thunk_free_lists (domain);
1587 size += sizeof (guint32);
1588 if (size < sizeof (MonoThunkFreeList))
1589 size = sizeof (MonoThunkFreeList);
1591 i = list_index_for_size (size);
1592 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1593 if ((*l)->size >= size) {
1594 MonoThunkFreeList *item = *l;
1596 return ((guint32*)item) + 1;
1600 /* no suitable item found - search lists of larger sizes */
1601 while (++i < NUM_FREE_LISTS) {
1602 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1605 g_assert (item->size > size);
1606 domain->thunk_free_lists [i] = item->next;
1607 return ((guint32*)item) + 1;
1610 /* still nothing found - allocate it */
1612 mono_counters_register ("Generic virtual thunk bytes",
1613 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1616 generic_virtual_thunks_size += size;
1618 p = (guint32 *)mono_domain_code_reserve (domain, size);
1621 mono_domain_lock (domain);
1622 if (!domain->generic_virtual_thunks)
1623 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1624 g_hash_table_insert (domain->generic_virtual_thunks, p, p);
1625 mono_domain_unlock (domain);
1631 * LOCKING: The domain lock must be held.
1634 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1636 MONO_REQ_GC_NEUTRAL_MODE;
1638 guint32 *p = (guint32 *)code;
1639 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1640 gboolean found = FALSE;
1642 mono_domain_lock (domain);
1643 if (!domain->generic_virtual_thunks)
1644 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1645 if (g_hash_table_lookup (domain->generic_virtual_thunks, l))
1647 mono_domain_unlock (domain);
1650 /* Not allocated by mono_method_alloc_generic_virtual_thunk (), i.e. AOT */
1652 init_thunk_free_lists (domain);
1654 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1655 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1656 int length = item->length;
1659 /* unlink the first item from the wait list */
1660 domain->thunk_free_lists [0] = item->next;
1661 domain->thunk_free_lists [0]->length = length - 1;
1663 i = list_index_for_size (item->size);
1665 /* put it in the free list */
1666 item->next = domain->thunk_free_lists [i];
1667 domain->thunk_free_lists [i] = item;
1671 if (domain->thunk_free_lists [1]) {
1672 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1673 domain->thunk_free_lists [0]->length++;
1675 g_assert (!domain->thunk_free_lists [0]);
1677 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1678 domain->thunk_free_lists [0]->length = 1;
1682 typedef struct _GenericVirtualCase {
1686 struct _GenericVirtualCase *next;
1687 } GenericVirtualCase;
1690 * get_generic_virtual_entries:
1692 * Return IMT entries for the generic virtual method instances and
1693 * variant interface methods for vtable slot
1696 static MonoImtBuilderEntry*
1697 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1699 MONO_REQ_GC_NEUTRAL_MODE;
1701 GenericVirtualCase *list;
1702 MonoImtBuilderEntry *entries;
1704 mono_domain_lock (domain);
1705 if (!domain->generic_virtual_cases)
1706 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1708 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1711 for (; list; list = list->next) {
1712 MonoImtBuilderEntry *entry;
1714 if (list->count < THUNK_THRESHOLD)
1717 entry = g_new0 (MonoImtBuilderEntry, 1);
1718 entry->key = list->method;
1719 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1720 entry->has_target_code = 1;
1722 entry->children = entries->children + 1;
1723 entry->next = entries;
1727 mono_domain_unlock (domain);
1729 /* FIXME: Leaking memory ? */
1734 * mono_method_add_generic_virtual_invocation:
1736 * @vtable_slot: pointer to the vtable slot
1737 * @method: the inflated generic virtual method
1738 * @code: the method's code
1740 * Registers a call via unmanaged code to a generic virtual method
1741 * instantiation or variant interface method. If the number of calls reaches a threshold
1742 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1743 * virtual method thunk.
1746 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1747 gpointer *vtable_slot,
1748 MonoMethod *method, gpointer code)
1750 MONO_REQ_GC_NEUTRAL_MODE;
1752 static gboolean inited = FALSE;
1753 static int num_added = 0;
1755 GenericVirtualCase *gvc, *list;
1756 MonoImtBuilderEntry *entries;
1760 mono_domain_lock (domain);
1761 if (!domain->generic_virtual_cases)
1762 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1764 /* Check whether the case was already added */
1765 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1768 if (gvc->method == method)
1773 /* If not found, make a new one */
1775 gvc = (GenericVirtualCase *)mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1776 gvc->method = method;
1779 gvc->next = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1781 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1784 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1790 if (++gvc->count == THUNK_THRESHOLD) {
1791 gpointer *old_thunk = (void **)*vtable_slot;
1792 gpointer vtable_trampoline = NULL;
1793 gpointer imt_trampoline = NULL;
1795 if ((gpointer)vtable_slot < (gpointer)vtable) {
1796 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1797 int imt_slot = MONO_IMT_SIZE + displacement;
1799 /* Force the rebuild of the thunk at the next call */
1800 imt_trampoline = callbacks.get_imt_trampoline (vtable, imt_slot);
1801 *vtable_slot = imt_trampoline;
1803 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline (vtable, (gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1805 entries = get_generic_virtual_entries (domain, vtable_slot);
1807 sorted = imt_sort_slot_entries (entries);
1809 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1813 MonoImtBuilderEntry *next = entries->next;
1818 for (i = 0; i < sorted->len; ++i)
1819 g_free (g_ptr_array_index (sorted, i));
1820 g_ptr_array_free (sorted, TRUE);
1823 #ifndef __native_client__
1824 /* We don't re-use any thunks as there is a lot of overhead */
1825 /* to deleting and re-using code in Native Client. */
1826 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1827 invalidate_generic_virtual_thunk (domain, old_thunk);
1831 mono_domain_unlock (domain);
1834 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, gboolean raise_on_error);
1837 * mono_class_vtable:
1838 * @domain: the application domain
1839 * @class: the class to initialize
1841 * VTables are domain specific because we create domain specific code, and
1842 * they contain the domain specific static class data.
1843 * On failure, NULL is returned, and class->exception_type is set.
1846 mono_class_vtable (MonoDomain *domain, MonoClass *klass)
1848 return mono_class_vtable_full (domain, klass, FALSE);
1852 * mono_class_vtable_full:
1853 * @domain: the application domain
1854 * @class: the class to initialize
1855 * @raise_on_error if an exception should be raised on failure or not
1857 * VTables are domain specific because we create domain specific code, and
1858 * they contain the domain specific static class data.
1861 mono_class_vtable_full (MonoDomain *domain, MonoClass *klass, gboolean raise_on_error)
1863 MONO_REQ_GC_UNSAFE_MODE;
1865 MonoClassRuntimeInfo *runtime_info;
1869 if (mono_class_has_failure (klass)) {
1871 mono_raise_exception (mono_class_get_exception_for_failure (klass));
1875 /* this check can be inlined in jitted code, too */
1876 runtime_info = klass->runtime_info;
1877 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1878 return runtime_info->domain_vtables [domain->domain_id];
1879 return mono_class_create_runtime_vtable (domain, klass, raise_on_error);
1883 * mono_class_try_get_vtable:
1884 * @domain: the application domain
1885 * @class: the class to initialize
1887 * This function tries to get the associated vtable from @class if
1888 * it was already created.
1891 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *klass)
1893 MONO_REQ_GC_NEUTRAL_MODE;
1895 MonoClassRuntimeInfo *runtime_info;
1899 runtime_info = klass->runtime_info;
1900 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1901 return runtime_info->domain_vtables [domain->domain_id];
1906 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1908 MONO_REQ_GC_NEUTRAL_MODE;
1910 size_t alloc_offset;
1913 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1914 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1915 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1917 if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1918 g_assert ((imt_table_bytes & 7) == 4);
1925 return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1929 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, gboolean raise_on_error)
1931 MONO_REQ_GC_UNSAFE_MODE;
1935 MonoClassRuntimeInfo *runtime_info, *old_info;
1936 MonoClassField *field;
1938 int i, vtable_slots;
1939 size_t imt_table_bytes;
1941 guint32 vtable_size, class_size;
1943 gpointer *interface_offsets;
1945 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1946 mono_domain_lock (domain);
1947 runtime_info = klass->runtime_info;
1948 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1949 mono_domain_unlock (domain);
1950 mono_loader_unlock ();
1951 return runtime_info->domain_vtables [domain->domain_id];
1953 if (!klass->inited || mono_class_has_failure (klass)) {
1954 if (!mono_class_init (klass) || mono_class_has_failure (klass)) {
1955 mono_domain_unlock (domain);
1956 mono_loader_unlock ();
1958 mono_raise_exception (mono_class_get_exception_for_failure (klass));
1963 /* Array types require that their element type be valid*/
1964 if (klass->byval_arg.type == MONO_TYPE_ARRAY || klass->byval_arg.type == MONO_TYPE_SZARRAY) {
1965 MonoClass *element_class = klass->element_class;
1966 if (!element_class->inited)
1967 mono_class_init (element_class);
1969 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1970 if (!mono_class_has_failure (element_class) && !element_class->vtable_size)
1971 mono_class_setup_vtable (element_class);
1973 if (mono_class_has_failure (element_class)) {
1974 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1975 if (!mono_class_has_failure (klass))
1976 mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
1977 mono_domain_unlock (domain);
1978 mono_loader_unlock ();
1980 mono_raise_exception (mono_class_get_exception_for_failure (klass));
1986 * For some classes, mono_class_init () already computed klass->vtable_size, and
1987 * that is all that is needed because of the vtable trampolines.
1989 if (!klass->vtable_size)
1990 mono_class_setup_vtable (klass);
1992 if (klass->generic_class && !klass->vtable)
1993 mono_class_check_vtable_constraints (klass, NULL);
1995 /* Initialize klass->has_finalize */
1996 mono_class_has_finalizer (klass);
1998 if (mono_class_has_failure (klass)) {
1999 mono_domain_unlock (domain);
2000 mono_loader_unlock ();
2002 mono_raise_exception (mono_class_get_exception_for_failure (klass));
2006 vtable_slots = klass->vtable_size;
2007 /* we add an additional vtable slot to store the pointer to static field data only when needed */
2008 class_size = mono_class_data_size (klass);
2012 if (klass->interface_offsets_count) {
2013 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
2014 mono_stats.imt_number_of_tables++;
2015 mono_stats.imt_tables_size += imt_table_bytes;
2017 imt_table_bytes = 0;
2020 vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
2022 mono_stats.used_class_count++;
2023 mono_stats.class_vtable_size += vtable_size;
2025 interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
2026 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2027 g_assert (!((gsize)vt & 7));
2030 vt->rank = klass->rank;
2031 vt->domain = domain;
2033 mono_class_compute_gc_descriptor (klass);
2035 * We can't use typed allocation in the non-root domains, since the
2036 * collector needs the GC descriptor stored in the vtable even after
2037 * the mempool containing the vtable is destroyed when the domain is
2038 * unloaded. An alternative might be to allocate vtables in the GC
2039 * heap, but this does not seem to work (it leads to crashes inside
2040 * libgc). If that approach is tried, two gc descriptors need to be
2041 * allocated for each class: one for the root domain, and one for all
2042 * other domains. The second descriptor should contain a bit for the
2043 * vtable field in MonoObject, since we can no longer assume the
2044 * vtable is reachable by other roots after the appdomain is unloaded.
2046 #ifdef HAVE_BOEHM_GC
2047 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
2048 vt->gc_descr = MONO_GC_DESCRIPTOR_NULL;
2051 vt->gc_descr = klass->gc_descr;
2053 gc_bits = mono_gc_get_vtable_bits (klass);
2054 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
2056 vt->gc_bits = gc_bits;
2059 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
2060 if (klass->has_static_refs) {
2061 MonoGCDescriptor statics_gc_descr;
2063 gsize default_bitmap [4] = {0};
2066 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
2067 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], klass->name_space, klass->name, class_size);*/
2068 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
2069 vt->vtable [klass->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr, MONO_ROOT_SOURCE_STATIC, "managed static variables");
2070 mono_domain_add_class_static_data (domain, klass, vt->vtable [klass->vtable_size], NULL);
2071 if (bitmap != default_bitmap)
2074 vt->vtable [klass->vtable_size] = mono_domain_alloc0 (domain, class_size);
2076 vt->has_static_fields = TRUE;
2077 mono_stats.class_static_data_size += class_size;
2081 while ((field = mono_class_get_fields (klass, &iter))) {
2082 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2084 if (mono_field_is_deleted (field))
2086 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2087 gint32 special_static = klass->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (klass, field);
2088 if (special_static != SPECIAL_STATIC_NONE) {
2089 guint32 size, offset;
2091 gsize default_bitmap [4] = {0};
2096 if (mono_type_is_reference (field->type)) {
2097 default_bitmap [0] = 1;
2099 bitmap = default_bitmap;
2100 } else if (mono_type_is_struct (field->type)) {
2101 fclass = mono_class_from_mono_type (field->type);
2102 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
2103 numbits = max_set + 1;
2105 default_bitmap [0] = 0;
2107 bitmap = default_bitmap;
2109 size = mono_type_size (field->type, &align);
2110 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
2111 if (!domain->special_static_fields)
2112 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2113 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2114 if (bitmap != default_bitmap)
2117 * This marks the field as special static to speed up the
2118 * checks in mono_field_static_get/set_value ().
2124 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2125 MonoClass *fklass = mono_class_from_mono_type (field->type);
2126 const char *data = mono_field_get_data (field);
2128 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2129 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2130 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2133 if (fklass->valuetype) {
2134 memcpy (t, data, mono_class_value_size (fklass, NULL));
2136 /* it's a pointer type: add check */
2137 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2144 vt->max_interface_id = klass->max_interface_id;
2145 vt->interface_bitmap = klass->interface_bitmap;
2147 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2148 // class->name, klass->interface_offsets_count);
2150 /* Initialize vtable */
2151 if (callbacks.get_vtable_trampoline) {
2152 // This also covers the AOT case
2153 for (i = 0; i < klass->vtable_size; ++i) {
2154 vt->vtable [i] = callbacks.get_vtable_trampoline (vt, i);
2157 mono_class_setup_vtable (klass);
2159 for (i = 0; i < klass->vtable_size; ++i) {
2162 cm = klass->vtable [i];
2164 vt->vtable [i] = callbacks.create_jit_trampoline (domain, cm, &error);
2165 if (!mono_error_ok (&error))
2166 mono_error_raise_exception (&error); /* FIXME: Don't raise here */
2171 if (imt_table_bytes) {
2172 /* Now that the vtable is full, we can actually fill up the IMT */
2173 for (i = 0; i < MONO_IMT_SIZE; ++i)
2174 interface_offsets [i] = callbacks.get_imt_trampoline (vt, i);
2178 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2179 * re-acquire them and check if another thread has created the vtable in the meantime.
2181 /* Special case System.MonoType to avoid infinite recursion */
2182 if (klass != mono_defaults.monotype_class) {
2183 /*FIXME check for OOM*/
2184 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, &error);
2185 mono_error_raise_exception (&error); /* FIXME don't raise here */
2187 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.monotype_class)
2188 /* This is unregistered in
2189 unregister_vtable_reflection_type() in
2191 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2194 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (klass));
2196 /* class_vtable_array keeps an array of created vtables
2198 g_ptr_array_add (domain->class_vtable_array, vt);
2199 /* klass->runtime_info is protected by the loader lock, both when
2200 * it it enlarged and when it is stored info.
2204 * Store the vtable in klass->runtime_info.
2205 * klass->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2207 mono_memory_barrier ();
2209 old_info = klass->runtime_info;
2210 if (old_info && old_info->max_domain >= domain->domain_id) {
2211 /* someone already created a large enough runtime info */
2212 old_info->domain_vtables [domain->domain_id] = vt;
2214 int new_size = domain->domain_id;
2216 new_size = MAX (new_size, old_info->max_domain);
2218 /* make the new size a power of two */
2220 while (new_size > i)
2223 /* this is a bounded memory retention issue: may want to
2224 * handle it differently when we'll have a rcu-like system.
2226 runtime_info = (MonoClassRuntimeInfo *)mono_image_alloc0 (klass->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2227 runtime_info->max_domain = new_size - 1;
2228 /* copy the stuff from the older info */
2230 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2232 runtime_info->domain_vtables [domain->domain_id] = vt;
2234 mono_memory_barrier ();
2235 klass->runtime_info = runtime_info;
2238 if (klass == mono_defaults.monotype_class) {
2239 /*FIXME check for OOM*/
2240 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, &error);
2241 mono_error_raise_exception (&error); /* FIXME don't raise here */
2243 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.monotype_class)
2244 /* This is unregistered in
2245 unregister_vtable_reflection_type() in
2247 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2250 mono_domain_unlock (domain);
2251 mono_loader_unlock ();
2253 /* make sure the parent is initialized */
2254 /*FIXME shouldn't this fail the current type?*/
2256 mono_class_vtable_full (domain, klass->parent, raise_on_error);
2261 #ifndef DISABLE_REMOTING
2263 * mono_class_proxy_vtable:
2264 * @domain: the application domain
2265 * @remove_class: the remote class
2267 * Creates a vtable for transparent proxies. It is basically
2268 * a copy of the real vtable of the class wrapped in @remote_class,
2269 * but all function pointers invoke the remoting functions, and
2270 * vtable->klass points to the transparent proxy class, and not to @class.
2273 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2275 MONO_REQ_GC_UNSAFE_MODE;
2278 MonoVTable *vt, *pvt;
2279 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2281 GSList *extra_interfaces = NULL;
2282 MonoClass *klass = remote_class->proxy_class;
2283 gpointer *interface_offsets;
2286 size_t imt_table_bytes;
2288 #ifdef COMPRESSED_INTERFACE_BITMAP
2292 vt = mono_class_vtable (domain, klass);
2293 g_assert (vt); /*FIXME property handle failure*/
2294 max_interface_id = vt->max_interface_id;
2296 /* Calculate vtable space for extra interfaces */
2297 for (j = 0; j < remote_class->interface_count; j++) {
2298 MonoClass* iclass = remote_class->interfaces[j];
2302 /*FIXME test for interfaces with variant generic arguments*/
2303 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, iclass->interface_id))
2304 continue; /* interface implemented by the class */
2305 if (g_slist_find (extra_interfaces, iclass))
2308 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2310 method_count = mono_class_num_methods (iclass);
2312 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2313 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2315 for (i = 0; i < ifaces->len; ++i) {
2316 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2317 /*FIXME test for interfaces with variant generic arguments*/
2318 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, ic->interface_id))
2319 continue; /* interface implemented by the class */
2320 if (g_slist_find (extra_interfaces, ic))
2322 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2323 method_count += mono_class_num_methods (ic);
2325 g_ptr_array_free (ifaces, TRUE);
2328 extra_interface_vtsize += method_count * sizeof (gpointer);
2329 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2332 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2333 mono_stats.imt_number_of_tables++;
2334 mono_stats.imt_tables_size += imt_table_bytes;
2336 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer);
2338 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2340 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2341 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2342 g_assert (!((gsize)pvt & 7));
2344 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer));
2346 pvt->klass = mono_defaults.transparent_proxy_class;
2347 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2348 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2350 /* initialize vtable */
2351 mono_class_setup_vtable (klass);
2352 for (i = 0; i < klass->vtable_size; ++i) {
2355 if ((cm = klass->vtable [i]))
2356 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2358 pvt->vtable [i] = NULL;
2361 if (klass->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2362 /* create trampolines for abstract methods */
2363 for (k = klass; k; k = k->parent) {
2365 gpointer iter = NULL;
2366 while ((m = mono_class_get_methods (k, &iter)))
2367 if (!pvt->vtable [m->slot])
2368 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2372 pvt->max_interface_id = max_interface_id;
2373 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2374 #ifdef COMPRESSED_INTERFACE_BITMAP
2375 bitmap = (uint8_t *)g_malloc0 (bsize);
2377 bitmap = (uint8_t *)mono_domain_alloc0 (domain, bsize);
2380 for (i = 0; i < klass->interface_offsets_count; ++i) {
2381 int interface_id = klass->interfaces_packed [i]->interface_id;
2382 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2385 if (extra_interfaces) {
2386 int slot = klass->vtable_size;
2392 /* Create trampolines for the methods of the interfaces */
2393 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2394 interf = (MonoClass *)list_item->data;
2396 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2400 while ((cm = mono_class_get_methods (interf, &iter)))
2401 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2403 slot += mono_class_num_methods (interf);
2407 /* Now that the vtable is full, we can actually fill up the IMT */
2408 build_imt (klass, pvt, domain, interface_offsets, extra_interfaces);
2409 if (extra_interfaces) {
2410 g_slist_free (extra_interfaces);
2413 #ifdef COMPRESSED_INTERFACE_BITMAP
2414 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2415 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2416 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2419 pvt->interface_bitmap = bitmap;
2424 #endif /* DISABLE_REMOTING */
2427 * mono_class_field_is_special_static:
2429 * Returns whether @field is a thread/context static field.
2432 mono_class_field_is_special_static (MonoClassField *field)
2434 MONO_REQ_GC_NEUTRAL_MODE
2436 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2438 if (mono_field_is_deleted (field))
2440 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2441 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2448 * mono_class_field_get_special_static_type:
2449 * @field: The MonoClassField describing the field.
2451 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2452 * SPECIAL_STATIC_NONE otherwise.
2455 mono_class_field_get_special_static_type (MonoClassField *field)
2457 MONO_REQ_GC_NEUTRAL_MODE
2459 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2460 return SPECIAL_STATIC_NONE;
2461 if (mono_field_is_deleted (field))
2462 return SPECIAL_STATIC_NONE;
2463 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2464 return field_is_special_static (field->parent, field);
2465 return SPECIAL_STATIC_NONE;
2469 * mono_class_has_special_static_fields:
2471 * Returns whenever @klass has any thread/context static fields.
2474 mono_class_has_special_static_fields (MonoClass *klass)
2476 MONO_REQ_GC_NEUTRAL_MODE
2478 MonoClassField *field;
2482 while ((field = mono_class_get_fields (klass, &iter))) {
2483 g_assert (field->parent == klass);
2484 if (mono_class_field_is_special_static (field))
2491 #ifndef DISABLE_REMOTING
2493 * create_remote_class_key:
2494 * Creates an array of pointers that can be used as a hash key for a remote class.
2495 * The first element of the array is the number of pointers.
2498 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2500 MONO_REQ_GC_NEUTRAL_MODE;
2505 if (remote_class == NULL) {
2506 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2507 key = (void **)g_malloc (sizeof(gpointer) * 3);
2508 key [0] = GINT_TO_POINTER (2);
2509 key [1] = mono_defaults.marshalbyrefobject_class;
2510 key [2] = extra_class;
2512 key = (void **)g_malloc (sizeof(gpointer) * 2);
2513 key [0] = GINT_TO_POINTER (1);
2514 key [1] = extra_class;
2517 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2518 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2519 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2520 key [1] = remote_class->proxy_class;
2522 // Keep the list of interfaces sorted
2523 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2524 if (extra_class && remote_class->interfaces [i] > extra_class) {
2525 key [j++] = extra_class;
2528 key [j] = remote_class->interfaces [i];
2531 key [j] = extra_class;
2533 // Replace the old class. The interface list is the same
2534 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2535 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2536 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2537 for (i = 0; i < remote_class->interface_count; i++)
2538 key [2 + i] = remote_class->interfaces [i];
2546 * copy_remote_class_key:
2548 * Make a copy of KEY in the domain and return the copy.
2551 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2553 MONO_REQ_GC_NEUTRAL_MODE
2555 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2556 gpointer *mp_key = (gpointer *)mono_domain_alloc (domain, key_size);
2558 memcpy (mp_key, key, key_size);
2564 * mono_remote_class:
2565 * @domain: the application domain
2566 * @class_name: name of the remote class
2568 * Creates and initializes a MonoRemoteClass object for a remote type.
2570 * Can raise an exception on failure.
2573 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2575 MONO_REQ_GC_UNSAFE_MODE;
2578 MonoRemoteClass *rc;
2579 gpointer* key, *mp_key;
2582 key = create_remote_class_key (NULL, proxy_class);
2584 mono_domain_lock (domain);
2585 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2589 mono_domain_unlock (domain);
2593 name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
2594 if (!mono_error_ok (&error)) {
2596 mono_domain_unlock (domain);
2597 mono_error_raise_exception (&error);
2600 mp_key = copy_remote_class_key (domain, key);
2604 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2605 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2606 rc->interface_count = 1;
2607 rc->interfaces [0] = proxy_class;
2608 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2610 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2611 rc->interface_count = 0;
2612 rc->proxy_class = proxy_class;
2615 rc->default_vtable = NULL;
2616 rc->xdomain_vtable = NULL;
2617 rc->proxy_class_name = name;
2618 #ifndef DISABLE_PERFCOUNTERS
2619 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2622 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2624 mono_domain_unlock (domain);
2629 * clone_remote_class:
2630 * Creates a copy of the remote_class, adding the provided class or interface
2632 static MonoRemoteClass*
2633 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2635 MONO_REQ_GC_NEUTRAL_MODE;
2637 MonoRemoteClass *rc;
2638 gpointer* key, *mp_key;
2640 key = create_remote_class_key (remote_class, extra_class);
2641 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2647 mp_key = copy_remote_class_key (domain, key);
2651 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2653 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2654 rc->proxy_class = remote_class->proxy_class;
2655 rc->interface_count = remote_class->interface_count + 1;
2657 // Keep the list of interfaces sorted, since the hash key of
2658 // the remote class depends on this
2659 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2660 if (remote_class->interfaces [i] > extra_class && i == j)
2661 rc->interfaces [j++] = extra_class;
2662 rc->interfaces [j] = remote_class->interfaces [i];
2665 rc->interfaces [j] = extra_class;
2667 // Replace the old class. The interface array is the same
2668 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2669 rc->proxy_class = extra_class;
2670 rc->interface_count = remote_class->interface_count;
2671 if (rc->interface_count > 0)
2672 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2675 rc->default_vtable = NULL;
2676 rc->xdomain_vtable = NULL;
2677 rc->proxy_class_name = remote_class->proxy_class_name;
2679 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2685 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2687 MONO_REQ_GC_UNSAFE_MODE;
2689 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2690 mono_domain_lock (domain);
2691 if (rp->target_domain_id != -1) {
2692 if (remote_class->xdomain_vtable == NULL)
2693 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2694 mono_domain_unlock (domain);
2695 mono_loader_unlock ();
2696 return remote_class->xdomain_vtable;
2698 if (remote_class->default_vtable == NULL) {
2701 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2702 klass = mono_class_from_mono_type (type);
2704 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)))
2705 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2708 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2711 mono_domain_unlock (domain);
2712 mono_loader_unlock ();
2713 return remote_class->default_vtable;
2717 * mono_upgrade_remote_class:
2718 * @domain: the application domain
2719 * @tproxy: the proxy whose remote class has to be upgraded.
2720 * @klass: class to which the remote class can be casted.
2722 * Updates the vtable of the remote class by adding the necessary method slots
2723 * and interface offsets so it can be safely casted to klass. klass can be a
2724 * class or an interface.
2727 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2729 MONO_REQ_GC_UNSAFE_MODE;
2731 MonoTransparentProxy *tproxy;
2732 MonoRemoteClass *remote_class;
2733 gboolean redo_vtable;
2735 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2736 mono_domain_lock (domain);
2738 tproxy = (MonoTransparentProxy*) proxy_object;
2739 remote_class = tproxy->remote_class;
2741 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2744 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2745 if (remote_class->interfaces [i] == klass)
2746 redo_vtable = FALSE;
2749 redo_vtable = (remote_class->proxy_class != klass);
2753 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2754 proxy_object->vtable = (MonoVTable *)mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2757 mono_domain_unlock (domain);
2758 mono_loader_unlock ();
2760 #endif /* DISABLE_REMOTING */
2764 * mono_object_get_virtual_method:
2765 * @obj: object to operate on.
2768 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2769 * the instance of a callvirt of method.
2772 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2774 MONO_REQ_GC_UNSAFE_MODE;
2777 MonoMethod **vtable;
2778 gboolean is_proxy = FALSE;
2779 MonoMethod *res = NULL;
2781 klass = mono_object_class (obj);
2782 #ifndef DISABLE_REMOTING
2783 if (klass == mono_defaults.transparent_proxy_class) {
2784 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2789 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2792 mono_class_setup_vtable (klass);
2793 vtable = klass->vtable;
2795 if (method->slot == -1) {
2796 /* method->slot might not be set for instances of generic methods */
2797 if (method->is_inflated) {
2798 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2799 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2802 g_assert_not_reached ();
2806 /* check method->slot is a valid index: perform isinstance? */
2807 if (method->slot != -1) {
2808 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2810 gboolean variance_used = FALSE;
2811 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2812 g_assert (iface_offset > 0);
2813 res = vtable [iface_offset + method->slot];
2816 res = vtable [method->slot];
2820 #ifndef DISABLE_REMOTING
2822 /* It may be an interface, abstract class method or generic method */
2823 if (!res || mono_method_signature (res)->generic_param_count)
2826 /* generic methods demand invoke_with_check */
2827 if (mono_method_signature (res)->generic_param_count)
2828 res = mono_marshal_get_remoting_invoke_with_check (res);
2831 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2832 res = mono_cominterop_get_invoke (res);
2835 res = mono_marshal_get_remoting_invoke (res);
2840 if (method->is_inflated) {
2842 /* Have to inflate the result */
2843 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, &error);
2844 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
2854 do_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2856 MONO_REQ_GC_UNSAFE_MODE;
2858 MonoObject *result = NULL;
2860 g_assert (callbacks.runtime_invoke);
2862 mono_error_init (error);
2864 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2865 mono_profiler_method_start_invoke (method);
2867 MONO_PREPARE_RESET_BLOCKING;
2869 result = callbacks.runtime_invoke (method, obj, params, exc, error);
2871 MONO_FINISH_RESET_BLOCKING;
2873 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2874 mono_profiler_method_end_invoke (method);
2876 if (!mono_error_ok (error))
2883 * mono_runtime_invoke:
2884 * @method: method to invoke
2885 * @obJ: object instance
2886 * @params: arguments to the method
2887 * @exc: exception information.
2889 * Invokes the method represented by @method on the object @obj.
2891 * obj is the 'this' pointer, it should be NULL for static
2892 * methods, a MonoObject* for object instances and a pointer to
2893 * the value type for value types.
2895 * The params array contains the arguments to the method with the
2896 * same convention: MonoObject* pointers for object instances and
2897 * pointers to the value type otherwise.
2899 * From unmanaged code you'll usually use the
2900 * mono_runtime_invoke() variant.
2902 * Note that this function doesn't handle virtual methods for
2903 * you, it will exec the exact method you pass: we still need to
2904 * expose a function to lookup the derived class implementation
2905 * of a virtual method (there are examples of this in the code,
2908 * You can pass NULL as the exc argument if you don't want to
2909 * catch exceptions, otherwise, *exc will be set to the exception
2910 * thrown, if any. if an exception is thrown, you can't use the
2911 * MonoObject* result from the function.
2913 * If the method returns a value type, it is boxed in an object
2917 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2922 res = mono_runtime_try_invoke (method, obj, params, exc, &error);
2923 if (*exc == NULL && !mono_error_ok(&error)) {
2924 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
2926 mono_error_cleanup (&error);
2928 res = mono_runtime_invoke_checked (method, obj, params, &error);
2929 mono_error_raise_exception (&error);
2935 * mono_runtime_try_invoke:
2936 * @method: method to invoke
2937 * @obJ: object instance
2938 * @params: arguments to the method
2939 * @exc: exception information.
2940 * @error: set on error
2942 * Invokes the method represented by @method on the object @obj.
2944 * obj is the 'this' pointer, it should be NULL for static
2945 * methods, a MonoObject* for object instances and a pointer to
2946 * the value type for value types.
2948 * The params array contains the arguments to the method with the
2949 * same convention: MonoObject* pointers for object instances and
2950 * pointers to the value type otherwise.
2952 * From unmanaged code you'll usually use the
2953 * mono_runtime_invoke() variant.
2955 * Note that this function doesn't handle virtual methods for
2956 * you, it will exec the exact method you pass: we still need to
2957 * expose a function to lookup the derived class implementation
2958 * of a virtual method (there are examples of this in the code,
2961 * For this function, you must not pass NULL as the exc argument if
2962 * you don't want to catch exceptions, use
2963 * mono_runtime_invoke_checked(). If an exception is thrown, you
2964 * can't use the MonoObject* result from the function.
2966 * If this method cannot be invoked, @error will be set and @exc and
2967 * the return value must not be used.
2969 * If the method returns a value type, it is boxed in an object
2973 mono_runtime_try_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError* error)
2975 MONO_REQ_GC_UNSAFE_MODE;
2977 g_assert (exc != NULL);
2979 if (mono_runtime_get_no_exec ())
2980 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2982 return do_runtime_invoke (method, obj, params, exc, error);
2986 * mono_runtime_invoke_checked:
2987 * @method: method to invoke
2988 * @obJ: object instance
2989 * @params: arguments to the method
2990 * @error: set on error
2992 * Invokes the method represented by @method on the object @obj.
2994 * obj is the 'this' pointer, it should be NULL for static
2995 * methods, a MonoObject* for object instances and a pointer to
2996 * the value type for value types.
2998 * The params array contains the arguments to the method with the
2999 * same convention: MonoObject* pointers for object instances and
3000 * pointers to the value type otherwise.
3002 * From unmanaged code you'll usually use the
3003 * mono_runtime_invoke() variant.
3005 * Note that this function doesn't handle virtual methods for
3006 * you, it will exec the exact method you pass: we still need to
3007 * expose a function to lookup the derived class implementation
3008 * of a virtual method (there are examples of this in the code,
3011 * If an exception is thrown, you can't use the MonoObject* result
3012 * from the function.
3014 * If this method cannot be invoked, @error will be set. If the
3015 * method throws an exception (and we're in coop mode) the exception
3016 * will be set in @error.
3018 * If the method returns a value type, it is boxed in an object
3022 mono_runtime_invoke_checked (MonoMethod *method, void *obj, void **params, MonoError* error)
3024 MONO_REQ_GC_UNSAFE_MODE;
3026 if (mono_runtime_get_no_exec ())
3027 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
3029 return do_runtime_invoke (method, obj, params, NULL, error);
3033 * mono_method_get_unmanaged_thunk:
3034 * @method: method to generate a thunk for.
3036 * Returns an unmanaged->managed thunk that can be used to call
3037 * a managed method directly from C.
3039 * The thunk's C signature closely matches the managed signature:
3041 * C#: public bool Equals (object obj);
3042 * C: typedef MonoBoolean (*Equals)(MonoObject*,
3043 * MonoObject*, MonoException**);
3045 * The 1st ("this") parameter must not be used with static methods:
3047 * C#: public static bool ReferenceEquals (object a, object b);
3048 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
3051 * The last argument must be a non-null pointer of a MonoException* pointer.
3052 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
3053 * exception has been thrown in managed code. Otherwise it will point
3054 * to the MonoException* caught by the thunk. In this case, the result of
3055 * the thunk is undefined:
3057 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
3058 * MonoException *ex = NULL;
3059 * Equals func = mono_method_get_unmanaged_thunk (method);
3060 * MonoBoolean res = func (thisObj, objToCompare, &ex);
3062 * // handle exception
3065 * The calling convention of the thunk matches the platform's default
3066 * convention. This means that under Windows, C declarations must
3067 * contain the __stdcall attribute:
3069 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
3070 * MonoObject*, MonoException**);
3074 * Value type arguments and return values are treated as they were objects:
3076 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
3077 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
3079 * Arguments must be properly boxed upon trunk's invocation, while return
3080 * values must be unboxed.
3083 mono_method_get_unmanaged_thunk (MonoMethod *method)
3085 MONO_REQ_GC_NEUTRAL_MODE;
3086 MONO_REQ_API_ENTRYPOINT;
3090 MONO_PREPARE_RESET_BLOCKING;
3091 method = mono_marshal_get_thunk_invoke_wrapper (method);
3092 res = mono_compile_method (method);
3093 MONO_FINISH_RESET_BLOCKING;
3099 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
3101 MONO_REQ_GC_UNSAFE_MODE;
3105 /* object fields cannot be byref, so we don't need a
3107 gpointer *p = (gpointer*)dest;
3114 case MONO_TYPE_BOOLEAN:
3116 case MONO_TYPE_U1: {
3117 guint8 *p = (guint8*)dest;
3118 *p = value ? *(guint8*)value : 0;
3123 case MONO_TYPE_CHAR: {
3124 guint16 *p = (guint16*)dest;
3125 *p = value ? *(guint16*)value : 0;
3128 #if SIZEOF_VOID_P == 4
3133 case MONO_TYPE_U4: {
3134 gint32 *p = (gint32*)dest;
3135 *p = value ? *(gint32*)value : 0;
3138 #if SIZEOF_VOID_P == 8
3143 case MONO_TYPE_U8: {
3144 gint64 *p = (gint64*)dest;
3145 *p = value ? *(gint64*)value : 0;
3148 case MONO_TYPE_R4: {
3149 float *p = (float*)dest;
3150 *p = value ? *(float*)value : 0;
3153 case MONO_TYPE_R8: {
3154 double *p = (double*)dest;
3155 *p = value ? *(double*)value : 0;
3158 case MONO_TYPE_STRING:
3159 case MONO_TYPE_SZARRAY:
3160 case MONO_TYPE_CLASS:
3161 case MONO_TYPE_OBJECT:
3162 case MONO_TYPE_ARRAY:
3163 mono_gc_wbarrier_generic_store (dest, deref_pointer ? *(MonoObject **)value : (MonoObject *)value);
3165 case MONO_TYPE_FNPTR:
3166 case MONO_TYPE_PTR: {
3167 gpointer *p = (gpointer*)dest;
3168 *p = deref_pointer? *(gpointer*)value: value;
3171 case MONO_TYPE_VALUETYPE:
3172 /* note that 't' and 'type->type' can be different */
3173 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3174 t = mono_class_enum_basetype (type->data.klass)->type;
3177 MonoClass *klass = mono_class_from_mono_type (type);
3178 int size = mono_class_value_size (klass, NULL);
3180 mono_gc_bzero_atomic (dest, size);
3182 mono_gc_wbarrier_value_copy (dest, value, 1, klass);
3185 case MONO_TYPE_GENERICINST:
3186 t = type->data.generic_class->container_class->byval_arg.type;
3189 g_error ("got type %x", type->type);
3194 * mono_field_set_value:
3195 * @obj: Instance object
3196 * @field: MonoClassField describing the field to set
3197 * @value: The value to be set
3199 * Sets the value of the field described by @field in the object instance @obj
3200 * to the value passed in @value. This method should only be used for instance
3201 * fields. For static fields, use mono_field_static_set_value.
3203 * The value must be on the native format of the field type.
3206 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3208 MONO_REQ_GC_UNSAFE_MODE;
3212 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3214 dest = (char*)obj + field->offset;
3215 mono_copy_value (field->type, dest, value, FALSE);
3219 * mono_field_static_set_value:
3220 * @field: MonoClassField describing the field to set
3221 * @value: The value to be set
3223 * Sets the value of the static field described by @field
3224 * to the value passed in @value.
3226 * The value must be on the native format of the field type.
3229 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3231 MONO_REQ_GC_UNSAFE_MODE;
3235 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3236 /* you cant set a constant! */
3237 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3239 if (field->offset == -1) {
3240 /* Special static */
3243 mono_domain_lock (vt->domain);
3244 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3245 mono_domain_unlock (vt->domain);
3246 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3248 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3250 mono_copy_value (field->type, dest, value, FALSE);
3254 * mono_vtable_get_static_field_data:
3256 * Internal use function: return a pointer to the memory holding the static fields
3257 * for a class or NULL if there are no static fields.
3258 * This is exported only for use by the debugger.
3261 mono_vtable_get_static_field_data (MonoVTable *vt)
3263 MONO_REQ_GC_NEUTRAL_MODE
3265 if (!vt->has_static_fields)
3267 return vt->vtable [vt->klass->vtable_size];
3271 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3273 MONO_REQ_GC_UNSAFE_MODE;
3277 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3278 if (field->offset == -1) {
3279 /* Special static */
3282 mono_domain_lock (vt->domain);
3283 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3284 mono_domain_unlock (vt->domain);
3285 src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3287 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3290 src = (guint8*)obj + field->offset;
3297 * mono_field_get_value:
3298 * @obj: Object instance
3299 * @field: MonoClassField describing the field to fetch information from
3300 * @value: pointer to the location where the value will be stored
3302 * Use this routine to get the value of the field @field in the object
3305 * The pointer provided by value must be of the field type, for reference
3306 * types this is a MonoObject*, for value types its the actual pointer to
3311 * mono_field_get_value (obj, int_field, &i);
3314 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3316 MONO_REQ_GC_UNSAFE_MODE;
3322 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3324 src = (char*)obj + field->offset;
3325 mono_copy_value (field->type, value, src, TRUE);
3329 * mono_field_get_value_object:
3330 * @domain: domain where the object will be created (if boxing)
3331 * @field: MonoClassField describing the field to fetch information from
3332 * @obj: The object instance for the field.
3334 * Returns: a new MonoObject with the value from the given field. If the
3335 * field represents a value type, the value is boxed.
3339 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3341 MONO_REQ_GC_UNSAFE_MODE;
3346 MonoVTable *vtable = NULL;
3348 gboolean is_static = FALSE;
3349 gboolean is_ref = FALSE;
3350 gboolean is_literal = FALSE;
3351 gboolean is_ptr = FALSE;
3352 MonoType *type = mono_field_get_type_checked (field, &error);
3354 if (!mono_error_ok (&error))
3355 mono_error_raise_exception (&error);
3357 switch (type->type) {
3358 case MONO_TYPE_STRING:
3359 case MONO_TYPE_OBJECT:
3360 case MONO_TYPE_CLASS:
3361 case MONO_TYPE_ARRAY:
3362 case MONO_TYPE_SZARRAY:
3367 case MONO_TYPE_BOOLEAN:
3370 case MONO_TYPE_CHAR:
3379 case MONO_TYPE_VALUETYPE:
3380 is_ref = type->byref;
3382 case MONO_TYPE_GENERICINST:
3383 is_ref = !mono_type_generic_inst_is_valuetype (type);
3389 g_error ("type 0x%x not handled in "
3390 "mono_field_get_value_object", type->type);
3394 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3397 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3401 vtable = mono_class_vtable_full (domain, field->parent, TRUE);
3402 if (!vtable->initialized)
3403 mono_runtime_class_init (vtable);
3411 get_default_field_value (domain, field, &o);
3412 } else if (is_static) {
3413 mono_field_static_get_value (vtable, field, &o);
3415 mono_field_get_value (obj, field, &o);
3421 static MonoMethod *m;
3427 MonoClass *ptr_klass = mono_class_get_pointer_class ();
3428 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3434 get_default_field_value (domain, field, v);
3435 } else if (is_static) {
3436 mono_field_static_get_value (vtable, field, v);
3438 mono_field_get_value (obj, field, v);
3441 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3442 args [0] = ptr ? *ptr : NULL;
3443 args [1] = mono_type_get_object_checked (mono_domain_get (), type, &error);
3444 mono_error_raise_exception (&error); /* FIXME don't raise here */
3446 o = mono_runtime_invoke_checked (m, NULL, args, &error);
3447 mono_error_raise_exception (&error); /* FIXME don't raise here */
3452 /* boxed value type */
3453 klass = mono_class_from_mono_type (type);
3455 if (mono_class_is_nullable (klass))
3456 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
3458 o = mono_object_new_checked (domain, klass, &error);
3459 mono_error_raise_exception (&error); /* FIXME don't raise here */
3460 v = ((gchar *) o) + sizeof (MonoObject);
3463 get_default_field_value (domain, field, v);
3464 } else if (is_static) {
3465 mono_field_static_get_value (vtable, field, v);
3467 mono_field_get_value (obj, field, v);
3474 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
3476 MONO_REQ_GC_UNSAFE_MODE;
3479 const char *p = blob;
3480 mono_metadata_decode_blob_size (p, &p);
3483 case MONO_TYPE_BOOLEAN:
3486 *(guint8 *) value = *p;
3488 case MONO_TYPE_CHAR:
3491 *(guint16*) value = read16 (p);
3495 *(guint32*) value = read32 (p);
3499 *(guint64*) value = read64 (p);
3502 readr4 (p, (float*) value);
3505 readr8 (p, (double*) value);
3507 case MONO_TYPE_STRING:
3508 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3510 case MONO_TYPE_CLASS:
3511 *(gpointer*) value = NULL;
3515 g_warning ("type 0x%02x should not be in constant table", type);
3521 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3523 MONO_REQ_GC_NEUTRAL_MODE;
3525 MonoTypeEnum def_type;
3528 data = mono_class_get_field_default_value (field, &def_type);
3529 mono_get_constant_value_from_blob (domain, def_type, data, value);
3533 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value)
3535 MONO_REQ_GC_UNSAFE_MODE;
3539 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3541 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3542 get_default_field_value (vt->domain, field, value);
3546 if (field->offset == -1) {
3547 /* Special static */
3548 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3549 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3551 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3553 mono_copy_value (field->type, value, src, TRUE);
3557 * mono_field_static_get_value:
3558 * @vt: vtable to the object
3559 * @field: MonoClassField describing the field to fetch information from
3560 * @value: where the value is returned
3562 * Use this routine to get the value of the static field @field value.
3564 * The pointer provided by value must be of the field type, for reference
3565 * types this is a MonoObject*, for value types its the actual pointer to
3570 * mono_field_static_get_value (vt, int_field, &i);
3573 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3575 MONO_REQ_GC_NEUTRAL_MODE;
3577 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value);
3581 * mono_property_set_value:
3582 * @prop: MonoProperty to set
3583 * @obj: instance object on which to act
3584 * @params: parameters to pass to the propery
3585 * @exc: optional exception
3587 * Invokes the property's set method with the given arguments on the
3588 * object instance obj (or NULL for static properties).
3590 * You can pass NULL as the exc argument if you don't want to
3591 * catch exceptions, otherwise, *exc will be set to the exception
3592 * thrown, if any. if an exception is thrown, you can't use the
3593 * MonoObject* result from the function.
3596 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3598 MONO_REQ_GC_UNSAFE_MODE;
3601 do_runtime_invoke (prop->set, obj, params, exc, &error);
3602 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3603 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3605 mono_error_raise_exception (&error); /* FIXME don't raise here */
3610 * mono_property_get_value:
3611 * @prop: MonoProperty to fetch
3612 * @obj: instance object on which to act
3613 * @params: parameters to pass to the propery
3614 * @exc: optional exception
3616 * Invokes the property's get method with the given arguments on the
3617 * object instance obj (or NULL for static properties).
3619 * You can pass NULL as the exc argument if you don't want to
3620 * catch exceptions, otherwise, *exc will be set to the exception
3621 * thrown, if any. if an exception is thrown, you can't use the
3622 * MonoObject* result from the function.
3624 * Returns: the value from invoking the get method on the property.
3627 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3629 MONO_REQ_GC_UNSAFE_MODE;
3632 MonoObject *val = do_runtime_invoke (prop->get, obj, params, exc, &error);
3633 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3634 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3636 mono_error_raise_exception (&error); /* FIXME don't raise here */
3643 * mono_nullable_init:
3644 * @buf: The nullable structure to initialize.
3645 * @value: the value to initialize from
3646 * @klass: the type for the object
3648 * Initialize the nullable structure pointed to by @buf from @value which
3649 * should be a boxed value type. The size of @buf should be able to hold
3650 * as much data as the @klass->instance_size (which is the number of bytes
3651 * that will be copies).
3653 * Since Nullables have variable structure, we can not define a C
3654 * structure for them.
3657 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3659 MONO_REQ_GC_UNSAFE_MODE;
3661 MonoClass *param_class = klass->cast_class;
3663 mono_class_setup_fields_locking (klass);
3664 g_assert (klass->fields_inited);
3666 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3667 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3669 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3671 if (param_class->has_references)
3672 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3674 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3676 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3681 * mono_nullable_box:
3682 * @buf: The buffer representing the data to be boxed
3683 * @klass: the type to box it as.
3685 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3689 mono_nullable_box (guint8 *buf, MonoClass *klass)
3691 MONO_REQ_GC_UNSAFE_MODE;
3695 MonoClass *param_class = klass->cast_class;
3697 mono_class_setup_fields_locking (klass);
3698 g_assert (klass->fields_inited);
3700 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3701 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3703 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3704 MonoObject *o = mono_object_new_checked (mono_domain_get (), param_class, &error);
3705 mono_error_raise_exception (&error); /* FIXME don't raise here */
3706 if (param_class->has_references)
3707 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3709 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3717 * mono_get_delegate_invoke:
3718 * @klass: The delegate class
3720 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3723 mono_get_delegate_invoke (MonoClass *klass)
3725 MONO_REQ_GC_NEUTRAL_MODE;
3729 /* This is called at runtime, so avoid the slower search in metadata */
3730 mono_class_setup_methods (klass);
3731 if (mono_class_has_failure (klass))
3733 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3738 * mono_get_delegate_begin_invoke:
3739 * @klass: The delegate class
3741 * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3744 mono_get_delegate_begin_invoke (MonoClass *klass)
3746 MONO_REQ_GC_NEUTRAL_MODE;
3750 /* This is called at runtime, so avoid the slower search in metadata */
3751 mono_class_setup_methods (klass);
3752 if (mono_class_has_failure (klass))
3754 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3759 * mono_get_delegate_end_invoke:
3760 * @klass: The delegate class
3762 * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3765 mono_get_delegate_end_invoke (MonoClass *klass)
3767 MONO_REQ_GC_NEUTRAL_MODE;
3771 /* This is called at runtime, so avoid the slower search in metadata */
3772 mono_class_setup_methods (klass);
3773 if (mono_class_has_failure (klass))
3775 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3780 * mono_runtime_delegate_invoke:
3781 * @delegate: pointer to a delegate object.
3782 * @params: parameters for the delegate.
3783 * @exc: Pointer to the exception result.
3785 * Invokes the delegate method @delegate with the parameters provided.
3787 * You can pass NULL as the exc argument if you don't want to
3788 * catch exceptions, otherwise, *exc will be set to the exception
3789 * thrown, if any. if an exception is thrown, you can't use the
3790 * MonoObject* result from the function.
3793 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3795 MONO_REQ_GC_UNSAFE_MODE;
3799 MonoClass *klass = delegate->vtable->klass;
3802 im = mono_get_delegate_invoke (klass);
3804 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3807 o = mono_runtime_try_invoke (im, delegate, params, exc, &error);
3808 if (*exc == NULL && !mono_error_ok (&error))
3809 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3811 mono_error_cleanup (&error);
3813 o = mono_runtime_invoke_checked (im, delegate, params, &error);
3814 mono_error_raise_exception (&error); /* FIXME don't raise here */
3820 static char **main_args = NULL;
3821 static int num_main_args = 0;
3824 * mono_runtime_get_main_args:
3826 * Returns: a MonoArray with the arguments passed to the main program
3829 mono_runtime_get_main_args (void)
3831 MONO_REQ_GC_UNSAFE_MODE;
3835 MonoDomain *domain = mono_domain_get ();
3837 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3839 for (i = 0; i < num_main_args; ++i)
3840 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3846 free_main_args (void)
3848 MONO_REQ_GC_NEUTRAL_MODE;
3852 for (i = 0; i < num_main_args; ++i)
3853 g_free (main_args [i]);
3860 * mono_runtime_set_main_args:
3861 * @argc: number of arguments from the command line
3862 * @argv: array of strings from the command line
3864 * Set the command line arguments from an embedding application that doesn't otherwise call
3865 * mono_runtime_run_main ().
3868 mono_runtime_set_main_args (int argc, char* argv[])
3870 MONO_REQ_GC_NEUTRAL_MODE;
3875 main_args = g_new0 (char*, argc);
3876 num_main_args = argc;
3878 for (i = 0; i < argc; ++i) {
3881 utf8_arg = mono_utf8_from_external (argv[i]);
3882 if (utf8_arg == NULL) {
3883 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
3884 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3888 main_args [i] = utf8_arg;
3895 * mono_runtime_run_main:
3896 * @method: the method to start the application with (usually Main)
3897 * @argc: number of arguments from the command line
3898 * @argv: array of strings from the command line
3899 * @exc: excetption results
3901 * Execute a standard Main() method (argc/argv contains the
3902 * executable name). This method also sets the command line argument value
3903 * needed by System.Environment.
3908 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3911 MONO_REQ_GC_UNSAFE_MODE;
3914 MonoArray *args = NULL;
3915 MonoDomain *domain = mono_domain_get ();
3916 gchar *utf8_fullpath;
3917 MonoMethodSignature *sig;
3919 g_assert (method != NULL);
3921 mono_thread_set_main (mono_thread_current ());
3923 main_args = g_new0 (char*, argc);
3924 num_main_args = argc;
3926 if (!g_path_is_absolute (argv [0])) {
3927 gchar *basename = g_path_get_basename (argv [0]);
3928 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3932 utf8_fullpath = mono_utf8_from_external (fullpath);
3933 if(utf8_fullpath == NULL) {
3934 /* Printing the arg text will cause glib to
3935 * whinge about "Invalid UTF-8", but at least
3936 * its relevant, and shows the problem text
3939 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3940 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3947 utf8_fullpath = mono_utf8_from_external (argv[0]);
3948 if(utf8_fullpath == NULL) {
3949 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3950 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3955 main_args [0] = utf8_fullpath;
3957 for (i = 1; i < argc; ++i) {
3960 utf8_arg=mono_utf8_from_external (argv[i]);
3961 if(utf8_arg==NULL) {
3962 /* Ditto the comment about Invalid UTF-8 here */
3963 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3964 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3968 main_args [i] = utf8_arg;
3973 sig = mono_method_signature (method);
3975 g_print ("Unable to load Main method.\n");
3979 if (sig->param_count) {
3980 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3981 for (i = 0; i < argc; ++i) {
3982 /* The encodings should all work, given that
3983 * we've checked all these args for the
3986 gchar *str = mono_utf8_from_external (argv [i]);
3987 MonoString *arg = mono_string_new (domain, str);
3988 mono_array_setref (args, i, arg);
3992 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3995 mono_assembly_set_main (method->klass->image->assembly);
3997 return mono_runtime_exec_main (method, args, exc);
4001 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4003 static MonoMethod *serialize_method;
4009 if (!serialize_method) {
4010 MonoClass *klass = mono_class_get_remoting_services_class ();
4011 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
4014 if (!serialize_method) {
4019 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
4024 array = mono_runtime_try_invoke (serialize_method, NULL, params, exc, &error);
4025 if (*exc == NULL && !mono_error_ok (&error))
4026 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert serialize_object to MonoError */
4028 mono_error_cleanup (&error);
4037 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4039 MONO_REQ_GC_UNSAFE_MODE;
4041 static MonoMethod *deserialize_method;
4047 if (!deserialize_method) {
4048 MonoClass *klass = mono_class_get_remoting_services_class ();
4049 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
4051 if (!deserialize_method) {
4059 result = mono_runtime_try_invoke (deserialize_method, NULL, params, exc, &error);
4060 if (*exc == NULL && !mono_error_ok (&error))
4061 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert deserialize_object to MonoError */
4063 mono_error_cleanup (&error);
4071 #ifndef DISABLE_REMOTING
4073 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
4075 MONO_REQ_GC_UNSAFE_MODE;
4077 static MonoMethod *get_proxy_method;
4080 MonoDomain *domain = mono_domain_get ();
4081 MonoRealProxy *real_proxy;
4082 MonoReflectionType *reflection_type;
4083 MonoTransparentProxy *transparent_proxy;
4085 if (!get_proxy_method)
4086 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
4088 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
4090 real_proxy = (MonoRealProxy*) mono_object_new_checked (domain, mono_defaults.real_proxy_class, &error);
4091 mono_error_raise_exception (&error); /* FIXME don't raise here */
4092 reflection_type = mono_type_get_object_checked (domain, &obj->vtable->klass->byval_arg, &error);
4093 mono_error_raise_exception (&error); /* FIXME don't raise here */
4095 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
4096 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
4100 transparent_proxy = (MonoTransparentProxy*) mono_runtime_try_invoke (get_proxy_method, real_proxy, NULL, exc, &error);
4101 if (*exc == NULL && !mono_error_ok (&error))
4102 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME change make_transparent_proxy outarg to MonoError */
4104 mono_error_cleanup (&error);
4108 return (MonoObject*) transparent_proxy;
4110 #endif /* DISABLE_REMOTING */
4113 * mono_object_xdomain_representation
4115 * @target_domain: a domain
4116 * @exc: pointer to a MonoObject*
4118 * Creates a representation of obj in the domain target_domain. This
4119 * is either a copy of obj arrived through via serialization and
4120 * deserialization or a proxy, depending on whether the object is
4121 * serializable or marshal by ref. obj must not be in target_domain.
4123 * If the object cannot be represented in target_domain, NULL is
4124 * returned and *exc is set to an appropriate exception.
4127 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
4129 MONO_REQ_GC_UNSAFE_MODE;
4131 MonoObject *deserialized = NULL;
4132 gboolean failure = FALSE;
4134 g_assert (exc != NULL);
4137 #ifndef DISABLE_REMOTING
4138 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
4139 deserialized = make_transparent_proxy (obj, &failure, exc);
4144 MonoDomain *domain = mono_domain_get ();
4145 MonoObject *serialized;
4147 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
4148 serialized = serialize_object (obj, &failure, exc);
4149 mono_domain_set_internal_with_options (target_domain, FALSE);
4151 deserialized = deserialize_object (serialized, &failure, exc);
4152 if (domain != target_domain)
4153 mono_domain_set_internal_with_options (domain, FALSE);
4156 return deserialized;
4159 /* Used in call_unhandled_exception_delegate */
4161 create_unhandled_exception_eventargs (MonoObject *exc)
4163 MONO_REQ_GC_UNSAFE_MODE;
4168 MonoMethod *method = NULL;
4169 MonoBoolean is_terminating = TRUE;
4172 klass = mono_class_get_unhandled_exception_event_args_class ();
4173 mono_class_init (klass);
4175 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4176 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
4180 args [1] = &is_terminating;
4182 obj = mono_object_new_checked (mono_domain_get (), klass, &error);
4183 mono_error_raise_exception (&error); /* FIXME don't raise here */
4185 mono_runtime_invoke_checked (method, obj, args, &error);
4186 mono_error_raise_exception (&error); /* FIXME don't raise here */
4191 /* Used in mono_unhandled_exception */
4193 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4194 MONO_REQ_GC_UNSAFE_MODE;
4196 MonoObject *e = NULL;
4198 MonoDomain *current_domain = mono_domain_get ();
4200 if (domain != current_domain)
4201 mono_domain_set_internal_with_options (domain, FALSE);
4203 g_assert (domain == mono_object_domain (domain->domain));
4205 if (mono_object_domain (exc) != domain) {
4206 MonoObject *serialization_exc;
4208 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
4210 if (serialization_exc) {
4212 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
4215 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4216 "System.Runtime.Serialization", "SerializationException",
4217 "Could not serialize unhandled exception.");
4221 g_assert (mono_object_domain (exc) == domain);
4223 pa [0] = domain->domain;
4224 pa [1] = create_unhandled_exception_eventargs (exc);
4225 mono_runtime_delegate_invoke (delegate, pa, &e);
4227 if (domain != current_domain)
4228 mono_domain_set_internal_with_options (current_domain, FALSE);
4232 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4233 if (!mono_error_ok (&error)) {
4234 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4235 mono_error_cleanup (&error);
4237 g_warning ("exception inside UnhandledException handler: %s\n", msg);
4243 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4246 * mono_runtime_unhandled_exception_policy_set:
4247 * @policy: the new policy
4249 * This is a VM internal routine.
4251 * Sets the runtime policy for handling unhandled exceptions.
4254 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4255 runtime_unhandled_exception_policy = policy;
4259 * mono_runtime_unhandled_exception_policy_get:
4261 * This is a VM internal routine.
4263 * Gets the runtime policy for handling unhandled exceptions.
4265 MonoRuntimeUnhandledExceptionPolicy
4266 mono_runtime_unhandled_exception_policy_get (void) {
4267 return runtime_unhandled_exception_policy;
4271 * mono_unhandled_exception:
4272 * @exc: exception thrown
4274 * This is a VM internal routine.
4276 * We call this function when we detect an unhandled exception
4277 * in the default domain.
4279 * It invokes the * UnhandledException event in AppDomain or prints
4280 * a warning to the console
4283 mono_unhandled_exception (MonoObject *exc)
4285 MONO_REQ_GC_UNSAFE_MODE;
4287 MonoClassField *field;
4288 MonoDomain *current_domain, *root_domain;
4289 MonoObject *current_appdomain_delegate = NULL, *root_appdomain_delegate = NULL;
4291 if (mono_class_has_parent (exc->vtable->klass, mono_defaults.threadabortexception_class))
4294 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4297 current_domain = mono_domain_get ();
4298 root_domain = mono_get_root_domain ();
4300 root_appdomain_delegate = mono_field_get_value_object (root_domain, field, (MonoObject*) root_domain->domain);
4301 if (current_domain != root_domain)
4302 current_appdomain_delegate = mono_field_get_value_object (current_domain, field, (MonoObject*) current_domain->domain);
4304 /* set exitcode only if we will abort the process */
4305 if (!current_appdomain_delegate && !root_appdomain_delegate) {
4306 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4307 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4309 mono_environment_exitcode_set (1);
4312 mono_print_unhandled_exception (exc);
4314 if (root_appdomain_delegate)
4315 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4316 if (current_appdomain_delegate)
4317 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4322 * mono_runtime_exec_managed_code:
4323 * @domain: Application domain
4324 * @main_func: function to invoke from the execution thread
4325 * @main_args: parameter to the main_func
4327 * Launch a new thread to execute a function
4329 * main_func is called back from the thread with main_args as the
4330 * parameter. The callback function is expected to start Main()
4331 * eventually. This function then waits for all managed threads to
4333 * It is not necesseray anymore to execute managed code in a subthread,
4334 * so this function should not be used anymore by default: just
4335 * execute the code and then call mono_thread_manage ().
4338 mono_runtime_exec_managed_code (MonoDomain *domain,
4339 MonoMainThreadFunc main_func,
4342 mono_thread_create (domain, main_func, main_args);
4344 mono_thread_manage ();
4348 * Execute a standard Main() method (args doesn't contain the
4352 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4354 MONO_REQ_GC_UNSAFE_MODE;
4360 MonoCustomAttrInfo* cinfo;
4361 gboolean has_stathread_attribute;
4362 MonoInternalThread* thread = mono_thread_internal_current ();
4368 domain = mono_object_domain (args);
4369 if (!domain->entry_assembly) {
4371 MonoAssembly *assembly;
4373 assembly = method->klass->image->assembly;
4374 domain->entry_assembly = assembly;
4375 /* Domains created from another domain already have application_base and configuration_file set */
4376 if (domain->setup->application_base == NULL) {
4377 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4380 if (domain->setup->configuration_file == NULL) {
4381 str = g_strconcat (assembly->image->name, ".config", NULL);
4382 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4384 mono_domain_set_options_from_config (domain);
4388 cinfo = mono_custom_attrs_from_method_checked (method, &error);
4389 mono_error_cleanup (&error); /* FIXME warn here? */
4391 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, mono_class_get_sta_thread_attribute_class ());
4393 mono_custom_attrs_free (cinfo);
4395 has_stathread_attribute = FALSE;
4397 if (has_stathread_attribute) {
4398 thread->apartment_state = ThreadApartmentState_STA;
4400 thread->apartment_state = ThreadApartmentState_MTA;
4402 mono_thread_init_apartment_state ();
4404 /* FIXME: check signature of method */
4405 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4408 res = mono_runtime_try_invoke (method, NULL, pa, exc, &error);
4409 if (*exc == NULL && !mono_error_ok (&error))
4410 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4412 mono_error_cleanup (&error);
4414 res = mono_runtime_invoke_checked (method, NULL, pa, &error);
4415 mono_error_raise_exception (&error); /* FIXME don't raise here */
4419 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4423 mono_environment_exitcode_set (rval);
4426 mono_runtime_try_invoke (method, NULL, pa, exc, &error);
4427 if (*exc == NULL && !mono_error_ok (&error))
4428 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4430 mono_error_cleanup (&error);
4432 mono_runtime_invoke_checked (method, NULL, pa, &error);
4433 mono_error_raise_exception (&error); /* FIXME don't raise here */
4439 /* If the return type of Main is void, only
4440 * set the exitcode if an exception was thrown
4441 * (we don't want to blow away an
4442 * explicitly-set exit code)
4445 mono_environment_exitcode_set (rval);
4453 * mono_runtime_invoke_array:
4454 * @method: method to invoke
4455 * @obJ: object instance
4456 * @params: arguments to the method
4457 * @exc: exception information.
4459 * Invokes the method represented by @method on the object @obj.
4461 * obj is the 'this' pointer, it should be NULL for static
4462 * methods, a MonoObject* for object instances and a pointer to
4463 * the value type for value types.
4465 * The params array contains the arguments to the method with the
4466 * same convention: MonoObject* pointers for object instances and
4467 * pointers to the value type otherwise. The _invoke_array
4468 * variant takes a C# object[] as the params argument (MonoArray
4469 * *params): in this case the value types are boxed inside the
4470 * respective reference representation.
4472 * From unmanaged code you'll usually use the
4473 * mono_runtime_invoke_checked() variant.
4475 * Note that this function doesn't handle virtual methods for
4476 * you, it will exec the exact method you pass: we still need to
4477 * expose a function to lookup the derived class implementation
4478 * of a virtual method (there are examples of this in the code,
4481 * You can pass NULL as the exc argument if you don't want to
4482 * catch exceptions, otherwise, *exc will be set to the exception
4483 * thrown, if any. if an exception is thrown, you can't use the
4484 * MonoObject* result from the function.
4486 * If the method returns a value type, it is boxed in an object
4490 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4493 MONO_REQ_GC_UNSAFE_MODE;
4496 MonoMethodSignature *sig = mono_method_signature (method);
4497 gpointer *pa = NULL;
4500 gboolean has_byref_nullables = FALSE;
4502 if (NULL != params) {
4503 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
4504 for (i = 0; i < mono_array_length (params); i++) {
4505 MonoType *t = sig->params [i];
4511 case MONO_TYPE_BOOLEAN:
4514 case MONO_TYPE_CHAR:
4523 case MONO_TYPE_VALUETYPE:
4524 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
4525 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4526 pa [i] = mono_array_get (params, MonoObject*, i);
4528 has_byref_nullables = TRUE;
4530 /* MS seems to create the objects if a null is passed in */
4531 if (!mono_array_get (params, MonoObject*, i)) {
4532 MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (sig->params [i]), &error);
4533 mono_error_raise_exception (&error); /* FIXME don't raise here */
4534 mono_array_setref (params, i, o);
4539 * We can't pass the unboxed vtype byref to the callee, since
4540 * that would mean the callee would be able to modify boxed
4541 * primitive types. So we (and MS) make a copy of the boxed
4542 * object, pass that to the callee, and replace the original
4543 * boxed object in the arg array with the copy.
4545 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4546 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
4547 mono_array_setref (params, i, copy);
4550 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4553 case MONO_TYPE_STRING:
4554 case MONO_TYPE_OBJECT:
4555 case MONO_TYPE_CLASS:
4556 case MONO_TYPE_ARRAY:
4557 case MONO_TYPE_SZARRAY:
4559 pa [i] = mono_array_addr (params, MonoObject*, i);
4560 // FIXME: I need to check this code path
4562 pa [i] = mono_array_get (params, MonoObject*, i);
4564 case MONO_TYPE_GENERICINST:
4566 t = &t->data.generic_class->container_class->this_arg;
4568 t = &t->data.generic_class->container_class->byval_arg;
4570 case MONO_TYPE_PTR: {
4573 /* The argument should be an IntPtr */
4574 arg = mono_array_get (params, MonoObject*, i);
4578 g_assert (arg->vtable->klass == mono_defaults.int_class);
4579 pa [i] = ((MonoIntPtr*)arg)->m_value;
4584 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
4589 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4592 if (mono_class_is_nullable (method->klass)) {
4593 /* Need to create a boxed vtype instead */
4599 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
4603 obj = mono_object_new_checked (mono_domain_get (), method->klass, &error);
4604 g_assert (obj && mono_error_ok (&error)); /*maybe we should raise a TLE instead?*/ /* FIXME don't swallow error */
4605 #ifndef DISABLE_REMOTING
4606 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
4607 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
4610 if (method->klass->valuetype)
4611 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
4614 } else if (method->klass->valuetype) {
4615 obj = mono_value_box (mono_domain_get (), method->klass, obj);
4619 mono_runtime_try_invoke (method, o, pa, exc, &error);
4620 if (*exc == NULL && !mono_error_ok (&error))
4621 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4623 mono_error_cleanup (&error);
4625 mono_runtime_invoke_checked (method, o, pa, &error);
4626 mono_error_raise_exception (&error); /* FIXME don't raise here */
4629 return (MonoObject *)obj;
4631 if (mono_class_is_nullable (method->klass)) {
4632 MonoObject *nullable;
4634 /* Convert the unboxed vtype into a Nullable structure */
4635 nullable = mono_object_new_checked (mono_domain_get (), method->klass, &error);
4636 mono_error_raise_exception (&error); /* FIXME don't raise here */
4638 mono_nullable_init ((guint8 *)mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
4639 obj = mono_object_unbox (nullable);
4642 /* obj must be already unboxed if needed */
4644 res = mono_runtime_try_invoke (method, obj, pa, exc, &error);
4645 if (*exc == NULL && !mono_error_ok (&error))
4646 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4648 mono_error_cleanup (&error);
4650 res = mono_runtime_invoke_checked (method, obj, pa, &error);
4651 mono_error_raise_exception (&error); /* FIXME don't raise here */
4654 if (sig->ret->type == MONO_TYPE_PTR) {
4655 MonoClass *pointer_class;
4656 static MonoMethod *box_method;
4658 MonoObject *box_exc;
4661 * The runtime-invoke wrapper returns a boxed IntPtr, need to
4662 * convert it to a Pointer object.
4664 pointer_class = mono_class_get_pointer_class ();
4666 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4668 g_assert (res->vtable->klass == mono_defaults.int_class);
4669 box_args [0] = ((MonoIntPtr*)res)->m_value;
4670 box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, &error);
4671 mono_error_raise_exception (&error); /* FIXME don't raise here */
4673 res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, &error);
4674 g_assert (box_exc == NULL);
4675 mono_error_assert_ok (&error);
4678 if (has_byref_nullables) {
4680 * The runtime invoke wrapper already converted byref nullables back,
4681 * and stored them in pa, we just need to copy them back to the
4684 for (i = 0; i < mono_array_length (params); i++) {
4685 MonoType *t = sig->params [i];
4687 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4688 mono_array_setref (params, i, pa [i]);
4698 * @klass: the class of the object that we want to create
4700 * Returns: a newly created object whose definition is
4701 * looked up using @klass. This will not invoke any constructors,
4702 * so the consumer of this routine has to invoke any constructors on
4703 * its own to initialize the object.
4705 * It returns NULL on failure.
4708 mono_object_new (MonoDomain *domain, MonoClass *klass)
4710 MONO_REQ_GC_UNSAFE_MODE;
4714 MonoObject * result = mono_object_new_checked (domain, klass, &error);
4716 mono_error_raise_exception (&error);
4721 ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
4723 MONO_REQ_GC_UNSAFE_MODE;
4727 MonoObject * result = mono_object_new_checked (domain, klass, &error);
4729 mono_error_raise_exception (&error);
4734 * mono_object_new_checked:
4735 * @klass: the class of the object that we want to create
4736 * @error: set on error
4738 * Returns: a newly created object whose definition is
4739 * looked up using @klass. This will not invoke any constructors,
4740 * so the consumer of this routine has to invoke any constructors on
4741 * its own to initialize the object.
4743 * It returns NULL on failure and sets @error.
4746 mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
4748 MONO_REQ_GC_UNSAFE_MODE;
4752 vtable = mono_class_vtable (domain, klass);
4753 g_assert (vtable); /* FIXME don't swallow the error */
4755 MonoObject *o = mono_object_new_specific_checked (vtable, error);
4760 * mono_object_new_pinned:
4762 * Same as mono_object_new, but the returned object will be pinned.
4763 * For SGEN, these objects will only be freed at appdomain unload.
4766 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
4768 MONO_REQ_GC_UNSAFE_MODE;
4772 mono_error_init (error);
4774 vtable = mono_class_vtable (domain, klass);
4775 g_assert (vtable); /* FIXME don't swallow the error */
4777 MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
4779 if (G_UNLIKELY (!o))
4780 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
4781 else if (G_UNLIKELY (vtable->klass->has_finalize))
4782 mono_object_register_finalizer (o);
4788 * mono_object_new_specific:
4789 * @vtable: the vtable of the object that we want to create
4791 * Returns: A newly created object with class and domain specified
4795 mono_object_new_specific (MonoVTable *vtable)
4798 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
4799 mono_error_raise_exception (&error);
4805 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
4807 MONO_REQ_GC_UNSAFE_MODE;
4811 mono_error_init (error);
4813 /* check for is_com_object for COM Interop */
4814 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
4817 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4820 MonoClass *klass = mono_class_get_activation_services_class ();
4823 mono_class_init (klass);
4825 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4827 mono_error_set_generic_error (error, "System", "NotSupportedException", "Linked away.");
4830 vtable->domain->create_proxy_for_type_method = im;
4833 pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
4834 if (!mono_error_ok (error))
4837 o = mono_runtime_invoke_checked (im, NULL, pa, error);
4838 if (!mono_error_ok (error))
4845 return mono_object_new_alloc_specific_checked (vtable, error);
4849 ves_icall_object_new_specific (MonoVTable *vtable)
4852 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
4853 mono_error_raise_exception (&error);
4859 * mono_object_new_alloc_specific:
4860 * @vtable: virtual table for the object.
4862 * This function allocates a new `MonoObject` with the type derived
4863 * from the @vtable information. If the class of this object has a
4864 * finalizer, then the object will be tracked for finalization.
4866 * This method might raise an exception on errors. Use the
4867 * `mono_object_new_fast_checked` method if you want to manually raise
4870 * Returns: the allocated object.
4873 mono_object_new_alloc_specific (MonoVTable *vtable)
4876 MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
4877 mono_error_raise_exception (&error);
4883 * mono_object_new_alloc_specific_checked:
4884 * @vtable: virtual table for the object.
4885 * @error: holds the error return value.
4887 * This function allocates a new `MonoObject` with the type derived
4888 * from the @vtable information. If the class of this object has a
4889 * finalizer, then the object will be tracked for finalization.
4891 * If there is not enough memory, the @error parameter will be set
4892 * and will contain a user-visible message with the amount of bytes
4893 * that were requested.
4895 * Returns: the allocated object, or NULL if there is not enough memory
4899 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
4901 MONO_REQ_GC_UNSAFE_MODE;
4905 mono_error_init (error);
4907 o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
4909 if (G_UNLIKELY (!o))
4910 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
4911 else if (G_UNLIKELY (vtable->klass->has_finalize))
4912 mono_object_register_finalizer (o);
4918 * mono_object_new_fast:
4919 * @vtable: virtual table for the object.
4921 * This function allocates a new `MonoObject` with the type derived
4922 * from the @vtable information. The returned object is not tracked
4923 * for finalization. If your object implements a finalizer, you should
4924 * use `mono_object_new_alloc_specific` instead.
4926 * This method might raise an exception on errors. Use the
4927 * `mono_object_new_fast_checked` method if you want to manually raise
4930 * Returns: the allocated object.
4933 mono_object_new_fast (MonoVTable *vtable)
4936 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
4937 mono_error_raise_exception (&error);
4943 * mono_object_new_fast_checked:
4944 * @vtable: virtual table for the object.
4945 * @error: holds the error return value.
4947 * This function allocates a new `MonoObject` with the type derived
4948 * from the @vtable information. The returned object is not tracked
4949 * for finalization. If your object implements a finalizer, you should
4950 * use `mono_object_new_alloc_specific_checked` instead.
4952 * If there is not enough memory, the @error parameter will be set
4953 * and will contain a user-visible message with the amount of bytes
4954 * that were requested.
4956 * Returns: the allocated object, or NULL if there is not enough memory
4960 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
4962 MONO_REQ_GC_UNSAFE_MODE;
4966 mono_error_init (error);
4968 o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
4970 if (G_UNLIKELY (!o))
4971 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
4977 ves_icall_object_new_fast (MonoVTable *vtable)
4980 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
4981 mono_error_raise_exception (&error);
4987 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
4989 MONO_REQ_GC_UNSAFE_MODE;
4993 mono_error_init (error);
4995 o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
4997 if (G_UNLIKELY (!o))
4998 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
4999 else if (G_UNLIKELY (vtable->klass->has_finalize))
5000 mono_object_register_finalizer (o);
5006 * mono_class_get_allocation_ftn:
5008 * @for_box: the object will be used for boxing
5009 * @pass_size_in_words:
5011 * Return the allocation function appropriate for the given class.
5015 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
5017 MONO_REQ_GC_NEUTRAL_MODE;
5019 *pass_size_in_words = FALSE;
5021 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass) || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
5022 return ves_icall_object_new_specific;
5024 if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
5026 return ves_icall_object_new_fast;
5029 * FIXME: This is actually slower than ves_icall_object_new_fast, because
5030 * of the overhead of parameter passing.
5033 *pass_size_in_words = TRUE;
5034 #ifdef GC_REDIRECT_TO_LOCAL
5035 return GC_local_gcj_fast_malloc;
5037 return GC_gcj_fast_malloc;
5042 return ves_icall_object_new_specific;
5046 * mono_object_new_from_token:
5047 * @image: Context where the type_token is hosted
5048 * @token: a token of the type that we want to create
5050 * Returns: A newly created object whose definition is
5051 * looked up using @token in the @image image
5054 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
5056 MONO_REQ_GC_UNSAFE_MODE;
5062 klass = mono_class_get_checked (image, token, &error);
5063 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
5065 result = mono_object_new_checked (domain, klass, &error);
5067 mono_error_raise_exception (&error); /* FIXME don't raise here */
5074 * mono_object_clone:
5075 * @obj: the object to clone
5077 * Returns: A newly created object who is a shallow copy of @obj
5080 mono_object_clone (MonoObject *obj)
5083 MonoObject *o = mono_object_clone_checked (obj, &error);
5084 mono_error_raise_exception (&error);
5090 mono_object_clone_checked (MonoObject *obj, MonoError *error)
5092 MONO_REQ_GC_UNSAFE_MODE;
5097 mono_error_init (error);
5099 size = obj->vtable->klass->instance_size;
5101 if (obj->vtable->klass->rank)
5102 return (MonoObject*)mono_array_clone ((MonoArray*)obj);
5104 o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
5106 if (G_UNLIKELY (!o)) {
5107 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5111 /* If the object doesn't contain references this will do a simple memmove. */
5112 mono_gc_wbarrier_object_copy (o, obj);
5114 if (obj->vtable->klass->has_finalize)
5115 mono_object_register_finalizer (o);
5120 * mono_array_full_copy:
5121 * @src: source array to copy
5122 * @dest: destination array
5124 * Copies the content of one array to another with exactly the same type and size.
5127 mono_array_full_copy (MonoArray *src, MonoArray *dest)
5129 MONO_REQ_GC_UNSAFE_MODE;
5132 MonoClass *klass = src->obj.vtable->klass;
5134 g_assert (klass == dest->obj.vtable->klass);
5136 size = mono_array_length (src);
5137 g_assert (size == mono_array_length (dest));
5138 size *= mono_array_element_size (klass);
5140 if (klass->element_class->valuetype) {
5141 if (klass->element_class->has_references)
5142 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
5144 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5146 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
5149 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5154 * mono_array_clone_in_domain:
5155 * @domain: the domain in which the array will be cloned into
5156 * @array: the array to clone
5158 * This routine returns a copy of the array that is hosted on the
5159 * specified MonoDomain.
5162 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
5164 MONO_REQ_GC_UNSAFE_MODE;
5170 MonoClass *klass = array->obj.vtable->klass;
5172 if (array->bounds == NULL) {
5173 size = mono_array_length (array);
5174 o = mono_array_new_full_checked (domain, klass, &size, NULL, &error);
5175 mono_error_raise_exception (&error); /* FIXME don't raise here */
5177 size *= mono_array_element_size (klass);
5179 if (klass->element_class->valuetype) {
5180 if (klass->element_class->has_references)
5181 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5183 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5185 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5188 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5193 sizes = (uintptr_t *)alloca (klass->rank * sizeof(intptr_t) * 2);
5194 size = mono_array_element_size (klass);
5195 for (i = 0; i < klass->rank; ++i) {
5196 sizes [i] = array->bounds [i].length;
5197 size *= array->bounds [i].length;
5198 sizes [i + klass->rank] = array->bounds [i].lower_bound;
5200 o = mono_array_new_full_checked (domain, klass, sizes, (intptr_t*)sizes + klass->rank, &error);
5201 mono_error_raise_exception (&error); /* FIXME don't raise here */
5203 if (klass->element_class->valuetype) {
5204 if (klass->element_class->has_references)
5205 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5207 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5209 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5212 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5220 * @array: the array to clone
5222 * Returns: A newly created array who is a shallow copy of @array
5225 mono_array_clone (MonoArray *array)
5227 MONO_REQ_GC_UNSAFE_MODE;
5229 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
5232 /* helper macros to check for overflow when calculating the size of arrays */
5233 #ifdef MONO_BIG_ARRAYS
5234 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
5235 #define MYGUINT_MAX MYGUINT64_MAX
5236 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5237 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
5238 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5239 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
5240 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
5242 #define MYGUINT32_MAX 4294967295U
5243 #define MYGUINT_MAX MYGUINT32_MAX
5244 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5245 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
5246 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5247 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
5248 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
5252 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
5254 MONO_REQ_GC_NEUTRAL_MODE;
5258 byte_len = mono_array_element_size (klass);
5259 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
5262 if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
5264 byte_len += MONO_SIZEOF_MONO_ARRAY;
5272 * mono_array_new_full:
5273 * @domain: domain where the object is created
5274 * @array_class: array class
5275 * @lengths: lengths for each dimension in the array
5276 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
5278 * This routine creates a new array objects with the given dimensions,
5279 * lower bounds and type.
5282 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
5285 MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
5286 mono_error_raise_exception (&error);
5292 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
5294 MONO_REQ_GC_UNSAFE_MODE;
5296 uintptr_t byte_len = 0, len, bounds_size;
5299 MonoArrayBounds *bounds;
5303 mono_error_init (error);
5305 if (!array_class->inited)
5306 mono_class_init (array_class);
5310 /* A single dimensional array with a 0 lower bound is the same as an szarray */
5311 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
5313 if (len > MONO_ARRAY_MAX_INDEX) {
5314 mono_error_set_generic_error (error, "System", "OverflowException", "");
5319 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
5321 for (i = 0; i < array_class->rank; ++i) {
5322 if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
5323 mono_error_set_generic_error (error, "System", "OverflowException", "");
5326 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5327 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5334 if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5335 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5341 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5342 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5345 byte_len = (byte_len + 3) & ~3;
5346 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5347 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5350 byte_len += bounds_size;
5353 * Following three lines almost taken from mono_object_new ():
5354 * they need to be kept in sync.
5356 vtable = mono_class_vtable_full (domain, array_class, TRUE);
5358 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5360 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5362 if (G_UNLIKELY (!o)) {
5363 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", byte_len);
5367 array = (MonoArray*)o;
5369 bounds = array->bounds;
5372 for (i = 0; i < array_class->rank; ++i) {
5373 bounds [i].length = lengths [i];
5375 bounds [i].lower_bound = lower_bounds [i];
5384 * @domain: domain where the object is created
5385 * @eclass: element class
5386 * @n: number of array elements
5388 * This routine creates a new szarray with @n elements of type @eclass.
5391 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5393 MONO_REQ_GC_UNSAFE_MODE;
5399 ac = mono_array_class_get (eclass, 1);
5402 arr = mono_array_new_specific_checked (mono_class_vtable_full (domain, ac, TRUE), n, &error);
5403 mono_error_raise_exception (&error); /* FIXME don't raise here */
5409 * mono_array_new_specific:
5410 * @vtable: a vtable in the appropriate domain for an initialized class
5411 * @n: number of array elements
5413 * This routine is a fast alternative to mono_array_new() for code which
5414 * can be sure about the domain it operates in.
5417 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5420 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5421 mono_error_raise_exception (&error); /* FIXME don't raise here */
5427 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
5429 MONO_REQ_GC_UNSAFE_MODE;
5434 mono_error_init (error);
5436 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
5437 mono_error_set_generic_error (error, "System", "OverflowException", "");
5441 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
5442 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5445 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
5447 if (G_UNLIKELY (!o)) {
5448 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", byte_len);
5452 return (MonoArray*)o;
5456 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
5459 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5460 mono_error_raise_exception (&error);
5466 * mono_string_new_utf16:
5467 * @text: a pointer to an utf16 string
5468 * @len: the length of the string
5470 * Returns: A newly created string object which contains @text.
5473 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
5475 MONO_REQ_GC_UNSAFE_MODE;
5478 MonoString *res = NULL;
5479 res = mono_string_new_utf16_checked (domain, text, len, &error);
5480 mono_error_raise_exception (&error);
5486 * mono_string_new_utf16_checked:
5487 * @text: a pointer to an utf16 string
5488 * @len: the length of the string
5489 * @error: written on error.
5491 * Returns: A newly created string object which contains @text.
5492 * On error, returns NULL and sets @error.
5495 mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
5497 MONO_REQ_GC_UNSAFE_MODE;
5501 mono_error_init (error);
5503 s = mono_string_new_size_checked (domain, len, error);
5505 memcpy (mono_string_chars (s), text, len * 2);
5511 * mono_string_new_utf32:
5512 * @text: a pointer to an utf32 string
5513 * @len: the length of the string
5515 * Returns: A newly created string object which contains @text.
5518 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
5520 MONO_REQ_GC_UNSAFE_MODE;
5524 mono_unichar2 *utf16_output = NULL;
5525 gint32 utf16_len = 0;
5526 GError *gerror = NULL;
5527 glong items_written;
5529 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
5532 g_error_free (gerror);
5534 while (utf16_output [utf16_len]) utf16_len++;
5536 s = mono_string_new_size_checked (domain, utf16_len, &error);
5537 mono_error_raise_exception (&error); /* FIXME don't raise here */
5539 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
5541 g_free (utf16_output);
5547 * mono_string_new_size:
5548 * @text: a pointer to an utf16 string
5549 * @len: the length of the string
5551 * Returns: A newly created string object of @len
5554 mono_string_new_size (MonoDomain *domain, gint32 len)
5557 MonoString *str = mono_string_new_size_checked (domain, len, &error);
5558 mono_error_raise_exception (&error);
5564 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
5566 MONO_REQ_GC_UNSAFE_MODE;
5572 mono_error_init (error);
5574 /* check for overflow */
5575 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
5576 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
5580 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
5581 g_assert (size > 0);
5583 vtable = mono_class_vtable (domain, mono_defaults.string_class);
5586 s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
5588 if (G_UNLIKELY (!s)) {
5589 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5597 * mono_string_new_len:
5598 * @text: a pointer to an utf8 string
5599 * @length: number of bytes in @text to consider
5601 * Returns: A newly created string object which contains @text.
5604 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
5606 MONO_REQ_GC_UNSAFE_MODE;
5609 GError *eg_error = NULL;
5610 MonoString *o = NULL;
5612 glong items_written;
5614 mono_error_init (&error);
5616 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
5619 o = mono_string_new_utf16_checked (domain, ut, items_written, &error);
5621 g_error_free (eg_error);
5625 mono_error_raise_exception (&error); /* FIXME don't raise here */
5631 * @text: a pointer to an utf8 string
5633 * Returns: A newly created string object which contains @text.
5635 * This function asserts if it cannot allocate a new string.
5637 * @deprecated Use mono_string_new_checked in new code.
5640 mono_string_new (MonoDomain *domain, const char *text)
5643 MonoString *res = NULL;
5644 res = mono_string_new_checked (domain, text, &error);
5645 mono_error_assert_ok (&error);
5650 * mono_string_new_checked:
5651 * @text: a pointer to an utf8 string
5652 * @merror: set on error
5654 * Returns: A newly created string object which contains @text.
5655 * On error returns NULL and sets @merror.
5658 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
5660 MONO_REQ_GC_UNSAFE_MODE;
5662 GError *eg_error = NULL;
5663 MonoString *o = NULL;
5665 glong items_written;
5668 mono_error_init (error);
5672 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &eg_error);
5675 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
5677 g_error_free (eg_error);
5680 mono_error_raise_exception (error);
5682 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
5687 MonoString *o = NULL;
5689 if (!g_utf8_validate (text, -1, &end)) {
5690 mono_error_set_argument (error, "text", "Not a valid utf8 string");
5694 len = g_utf8_strlen (text, -1);
5695 o = mono_string_new_size_checked (domain, len, error);
5698 str = mono_string_chars (o);
5700 while (text < end) {
5701 *str++ = g_utf8_get_char (text);
5702 text = g_utf8_next_char (text);
5711 * mono_string_new_wrapper:
5712 * @text: pointer to utf8 characters.
5714 * Helper function to create a string object from @text in the current domain.
5717 mono_string_new_wrapper (const char *text)
5719 MONO_REQ_GC_UNSAFE_MODE;
5721 MonoDomain *domain = mono_domain_get ();
5724 return mono_string_new (domain, text);
5731 * @class: the class of the value
5732 * @value: a pointer to the unboxed data
5734 * Returns: A newly created object which contains @value.
5737 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
5739 MONO_REQ_GC_UNSAFE_MODE;
5746 g_assert (klass->valuetype);
5747 if (mono_class_is_nullable (klass))
5748 return mono_nullable_box ((guint8 *)value, klass);
5750 vtable = mono_class_vtable (domain, klass);
5753 size = mono_class_instance_size (klass);
5754 res = mono_object_new_alloc_specific_checked (vtable, &error);
5755 mono_error_raise_exception (&error); /* FIXME don't raise here */
5757 size = size - sizeof (MonoObject);
5760 g_assert (size == mono_class_value_size (klass, NULL));
5761 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
5763 #if NO_UNALIGNED_ACCESS
5764 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5768 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
5771 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
5774 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
5777 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
5780 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5784 if (klass->has_finalize)
5785 mono_object_register_finalizer (res);
5791 * @dest: destination pointer
5792 * @src: source pointer
5793 * @klass: a valuetype class
5795 * Copy a valuetype from @src to @dest. This function must be used
5796 * when @klass contains references fields.
5799 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
5801 MONO_REQ_GC_UNSAFE_MODE;
5803 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
5807 * mono_value_copy_array:
5808 * @dest: destination array
5809 * @dest_idx: index in the @dest array
5810 * @src: source pointer
5811 * @count: number of items
5813 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
5814 * This function must be used when @klass contains references fields.
5815 * Overlap is handled.
5818 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
5820 MONO_REQ_GC_UNSAFE_MODE;
5822 int size = mono_array_element_size (dest->obj.vtable->klass);
5823 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
5824 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
5825 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
5829 * mono_object_get_domain:
5830 * @obj: object to query
5832 * Returns: the MonoDomain where the object is hosted
5835 mono_object_get_domain (MonoObject *obj)
5837 MONO_REQ_GC_UNSAFE_MODE;
5839 return mono_object_domain (obj);
5843 * mono_object_get_class:
5844 * @obj: object to query
5846 * Use this function to obtain the `MonoClass*` for a given `MonoObject`.
5848 * Returns: the MonoClass of the object.
5851 mono_object_get_class (MonoObject *obj)
5853 MONO_REQ_GC_UNSAFE_MODE;
5855 return mono_object_class (obj);
5858 * mono_object_get_size:
5859 * @o: object to query
5861 * Returns: the size, in bytes, of @o
5864 mono_object_get_size (MonoObject* o)
5866 MONO_REQ_GC_UNSAFE_MODE;
5868 MonoClass* klass = mono_object_class (o);
5869 if (klass == mono_defaults.string_class) {
5870 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
5871 } else if (o->vtable->rank) {
5872 MonoArray *array = (MonoArray*)o;
5873 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
5874 if (array->bounds) {
5877 size += sizeof (MonoArrayBounds) * o->vtable->rank;
5881 return mono_class_instance_size (klass);
5886 * mono_object_unbox:
5887 * @obj: object to unbox
5889 * Returns: a pointer to the start of the valuetype boxed in this
5892 * This method will assert if the object passed is not a valuetype.
5895 mono_object_unbox (MonoObject *obj)
5897 MONO_REQ_GC_UNSAFE_MODE;
5899 /* add assert for valuetypes? */
5900 g_assert (obj->vtable->klass->valuetype);
5901 return ((char*)obj) + sizeof (MonoObject);
5905 * mono_object_isinst:
5907 * @klass: a pointer to a class
5909 * Returns: @obj if @obj is derived from @klass
5912 mono_object_isinst (MonoObject *obj, MonoClass *klass)
5914 MONO_REQ_GC_UNSAFE_MODE;
5917 mono_class_init (klass);
5919 if (mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
5920 return mono_object_isinst_mbyref (obj, klass);
5925 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
5929 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
5931 MONO_REQ_GC_UNSAFE_MODE;
5941 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5942 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
5946 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
5947 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
5950 MonoClass *oklass = vt->klass;
5951 if (mono_class_is_transparent_proxy (oklass))
5952 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
5954 mono_class_setup_supertypes (klass);
5955 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
5958 #ifndef DISABLE_REMOTING
5959 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
5961 MonoDomain *domain = mono_domain_get ();
5963 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
5964 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
5965 MonoMethod *im = NULL;
5968 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
5970 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
5971 im = mono_object_get_virtual_method (rp, im);
5974 pa [0] = mono_type_get_object_checked (domain, &klass->byval_arg, &error);
5975 mono_error_raise_exception (&error); /* FIXME don't raise here */
5978 res = mono_runtime_invoke_checked (im, rp, pa, &error);
5979 mono_error_raise_exception (&error); /* FIXME don't raise here */
5981 if (*(MonoBoolean *) mono_object_unbox(res)) {
5982 /* Update the vtable of the remote type, so it can safely cast to this new type */
5983 mono_upgrade_remote_class (domain, obj, klass);
5987 #endif /* DISABLE_REMOTING */
5992 * mono_object_castclass_mbyref:
5994 * @klass: a pointer to a class
5996 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
5999 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
6001 MONO_REQ_GC_UNSAFE_MODE;
6003 if (!obj) return NULL;
6004 if (mono_object_isinst_mbyref (obj, klass)) return obj;
6006 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
6008 "InvalidCastException"));
6013 MonoDomain *orig_domain;
6019 str_lookup (MonoDomain *domain, gpointer user_data)
6021 MONO_REQ_GC_UNSAFE_MODE;
6023 LDStrInfo *info = (LDStrInfo *)user_data;
6024 if (info->res || domain == info->orig_domain)
6026 info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
6030 mono_string_get_pinned (MonoString *str, MonoError *error)
6032 MONO_REQ_GC_UNSAFE_MODE;
6034 mono_error_init (error);
6036 /* We only need to make a pinned version of a string if this is a moving GC */
6037 if (!mono_gc_is_moving ())
6041 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
6042 news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
6044 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
6045 news->length = mono_string_length (str);
6047 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6053 mono_string_is_interned_lookup (MonoString *str, int insert)
6055 MONO_REQ_GC_UNSAFE_MODE;
6058 MonoGHashTable *ldstr_table;
6059 MonoString *s, *res;
6062 domain = ((MonoObject *)str)->vtable->domain;
6063 ldstr_table = domain->ldstr_table;
6065 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6071 /* Allocate outside the lock */
6073 s = mono_string_get_pinned (str, &error);
6074 mono_error_raise_exception (&error); /* FIXME don't raise here */
6077 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6082 mono_g_hash_table_insert (ldstr_table, s, s);
6087 LDStrInfo ldstr_info;
6088 ldstr_info.orig_domain = domain;
6089 ldstr_info.ins = str;
6090 ldstr_info.res = NULL;
6092 mono_domain_foreach (str_lookup, &ldstr_info);
6093 if (ldstr_info.res) {
6095 * the string was already interned in some other domain:
6096 * intern it in the current one as well.
6098 mono_g_hash_table_insert (ldstr_table, str, str);
6108 * mono_string_is_interned:
6109 * @o: String to probe
6111 * Returns whether the string has been interned.
6114 mono_string_is_interned (MonoString *o)
6116 MONO_REQ_GC_UNSAFE_MODE;
6118 return mono_string_is_interned_lookup (o, FALSE);
6122 * mono_string_intern:
6123 * @o: String to intern
6125 * Interns the string passed.
6126 * Returns: The interned string.
6129 mono_string_intern (MonoString *str)
6131 MONO_REQ_GC_UNSAFE_MODE;
6133 return mono_string_is_interned_lookup (str, TRUE);
6138 * @domain: the domain where the string will be used.
6139 * @image: a metadata context
6140 * @idx: index into the user string table.
6142 * Implementation for the ldstr opcode.
6143 * Returns: a loaded string from the @image/@idx combination.
6146 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
6148 MONO_REQ_GC_UNSAFE_MODE;
6150 if (image->dynamic) {
6151 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
6154 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6155 return NULL; /*FIXME we should probably be raising an exception here*/
6156 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
6161 * mono_ldstr_metadata_sig
6162 * @domain: the domain for the string
6163 * @sig: the signature of a metadata string
6165 * Returns: a MonoString for a string stored in the metadata
6168 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
6170 MONO_REQ_GC_UNSAFE_MODE;
6173 const char *str = sig;
6174 MonoString *o, *interned;
6177 len2 = mono_metadata_decode_blob_size (str, &str);
6180 o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, &error);
6181 mono_error_raise_exception (&error); /* FIXME don't raise here */
6182 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
6185 guint16 *p2 = (guint16*)mono_string_chars (o);
6186 for (i = 0; i < len2; ++i) {
6187 *p2 = GUINT16_FROM_LE (*p2);
6193 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6196 return interned; /* o will get garbage collected */
6198 o = mono_string_get_pinned (o, &error);
6199 mono_error_raise_exception (&error); /* FIXME don't raise here */
6202 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6204 mono_g_hash_table_insert (domain->ldstr_table, o, o);
6214 * mono_string_to_utf8:
6215 * @s: a System.String
6217 * Returns the UTF8 representation for @s.
6218 * The resulting buffer needs to be freed with mono_free().
6220 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
6223 mono_string_to_utf8 (MonoString *s)
6225 MONO_REQ_GC_UNSAFE_MODE;
6228 char *result = mono_string_to_utf8_checked (s, &error);
6230 if (!mono_error_ok (&error))
6231 mono_error_raise_exception (&error);
6236 * mono_string_to_utf8_checked:
6237 * @s: a System.String
6238 * @error: a MonoError.
6240 * Converts a MonoString to its UTF8 representation. May fail; check
6241 * @error to determine whether the conversion was successful.
6242 * The resulting buffer should be freed with mono_free().
6245 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
6247 MONO_REQ_GC_UNSAFE_MODE;
6251 GError *gerror = NULL;
6253 mono_error_init (error);
6259 return g_strdup ("");
6261 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
6263 mono_error_set_argument (error, "string", "%s", gerror->message);
6264 g_error_free (gerror);
6267 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6268 if (s->length > written) {
6269 /* allocate the total length and copy the part of the string that has been converted */
6270 char *as2 = (char *)g_malloc0 (s->length);
6271 memcpy (as2, as, written);
6280 * mono_string_to_utf8_ignore:
6283 * Converts a MonoString to its UTF8 representation. Will ignore
6284 * invalid surrogate pairs.
6285 * The resulting buffer should be freed with mono_free().
6289 mono_string_to_utf8_ignore (MonoString *s)
6291 MONO_REQ_GC_UNSAFE_MODE;
6300 return g_strdup ("");
6302 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
6304 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6305 if (s->length > written) {
6306 /* allocate the total length and copy the part of the string that has been converted */
6307 char *as2 = (char *)g_malloc0 (s->length);
6308 memcpy (as2, as, written);
6317 * mono_string_to_utf8_image_ignore:
6318 * @s: a System.String
6320 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
6323 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
6325 MONO_REQ_GC_UNSAFE_MODE;
6327 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
6331 * mono_string_to_utf8_mp_ignore:
6332 * @s: a System.String
6334 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
6337 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
6339 MONO_REQ_GC_UNSAFE_MODE;
6341 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
6346 * mono_string_to_utf16:
6349 * Return an null-terminated array of the utf-16 chars
6350 * contained in @s. The result must be freed with g_free().
6351 * This is a temporary helper until our string implementation
6352 * is reworked to always include the null terminating char.
6355 mono_string_to_utf16 (MonoString *s)
6357 MONO_REQ_GC_UNSAFE_MODE;
6364 as = (char *)g_malloc ((s->length * 2) + 2);
6365 as [(s->length * 2)] = '\0';
6366 as [(s->length * 2) + 1] = '\0';
6369 return (gunichar2 *)(as);
6372 memcpy (as, mono_string_chars(s), s->length * 2);
6373 return (gunichar2 *)(as);
6377 * mono_string_to_utf32:
6380 * Return an null-terminated array of the UTF-32 (UCS-4) chars
6381 * contained in @s. The result must be freed with g_free().
6384 mono_string_to_utf32 (MonoString *s)
6386 MONO_REQ_GC_UNSAFE_MODE;
6388 mono_unichar4 *utf32_output = NULL;
6389 GError *error = NULL;
6390 glong items_written;
6395 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
6398 g_error_free (error);
6400 return utf32_output;
6404 * mono_string_from_utf16:
6405 * @data: the UTF16 string (LPWSTR) to convert
6407 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
6409 * Returns: a MonoString.
6412 mono_string_from_utf16 (gunichar2 *data)
6414 MONO_REQ_GC_UNSAFE_MODE;
6417 MonoString *res = NULL;
6418 MonoDomain *domain = mono_domain_get ();
6424 while (data [len]) len++;
6426 res = mono_string_new_utf16_checked (domain, data, len, &error);
6427 mono_error_raise_exception (&error); /* FIXME don't raise here */
6432 * mono_string_from_utf32:
6433 * @data: the UTF32 string (LPWSTR) to convert
6435 * Converts a UTF32 (UCS-4)to a MonoString.
6437 * Returns: a MonoString.
6440 mono_string_from_utf32 (mono_unichar4 *data)
6442 MONO_REQ_GC_UNSAFE_MODE;
6444 MonoString* result = NULL;
6445 mono_unichar2 *utf16_output = NULL;
6446 GError *error = NULL;
6447 glong items_written;
6453 while (data [len]) len++;
6455 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &error);
6458 g_error_free (error);
6460 result = mono_string_from_utf16 (utf16_output);
6461 g_free (utf16_output);
6466 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
6468 MONO_REQ_GC_UNSAFE_MODE;
6475 r = mono_string_to_utf8_ignore (s);
6477 r = mono_string_to_utf8_checked (s, error);
6478 if (!mono_error_ok (error))
6485 len = strlen (r) + 1;
6487 mp_s = (char *)mono_mempool_alloc (mp, len);
6489 mp_s = (char *)mono_image_alloc (image, len);
6491 memcpy (mp_s, r, len);
6499 * mono_string_to_utf8_image:
6500 * @s: a System.String
6502 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
6505 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
6507 MONO_REQ_GC_UNSAFE_MODE;
6509 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
6513 * mono_string_to_utf8_mp:
6514 * @s: a System.String
6516 * Same as mono_string_to_utf8, but allocate the string from a mempool.
6519 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
6521 MONO_REQ_GC_UNSAFE_MODE;
6523 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
6527 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
6530 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
6532 eh_callbacks = *cbs;
6535 MonoRuntimeExceptionHandlingCallbacks *
6536 mono_get_eh_callbacks (void)
6538 return &eh_callbacks;
6542 * mono_raise_exception:
6543 * @ex: exception object
6545 * Signal the runtime that the exception @ex has been raised in unmanaged code.
6548 mono_raise_exception (MonoException *ex)
6550 MONO_REQ_GC_UNSAFE_MODE;
6553 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
6554 * that will cause gcc to omit the function epilog, causing problems when
6555 * the JIT tries to walk the stack, since the return address on the stack
6556 * will point into the next function in the executable, not this one.
6558 eh_callbacks.mono_raise_exception (ex);
6562 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
6564 MONO_REQ_GC_UNSAFE_MODE;
6566 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
6570 * mono_wait_handle_new:
6571 * @domain: Domain where the object will be created
6572 * @handle: Handle for the wait handle
6574 * Returns: A new MonoWaitHandle created in the given domain for the given handle
6577 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
6579 MONO_REQ_GC_UNSAFE_MODE;
6582 MonoWaitHandle *res;
6583 gpointer params [1];
6584 static MonoMethod *handle_set;
6586 res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, &error);
6587 mono_error_raise_exception (&error); /* FIXME don't raise here */
6589 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
6591 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
6593 params [0] = &handle;
6595 mono_runtime_invoke_checked (handle_set, res, params, &error);
6596 mono_error_raise_exception (&error); /* FIXME don't raise here */
6602 mono_wait_handle_get_handle (MonoWaitHandle *handle)
6604 MONO_REQ_GC_UNSAFE_MODE;
6606 static MonoClassField *f_safe_handle = NULL;
6609 if (!f_safe_handle) {
6610 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safeWaitHandle");
6611 g_assert (f_safe_handle);
6614 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
6620 mono_runtime_capture_context (MonoDomain *domain)
6622 MONO_REQ_GC_UNSAFE_MODE;
6624 RuntimeInvokeFunction runtime_invoke;
6626 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
6627 MonoMethod *method = mono_get_context_capture_method ();
6628 MonoMethod *wrapper;
6631 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
6632 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
6633 domain->capture_context_method = mono_compile_method (method);
6636 runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
6638 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
6641 * mono_async_result_new:
6642 * @domain:domain where the object will be created.
6643 * @handle: wait handle.
6644 * @state: state to pass to AsyncResult
6645 * @data: C closure data.
6647 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
6648 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
6652 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
6654 MONO_REQ_GC_UNSAFE_MODE;
6657 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, &error);
6658 mono_error_raise_exception (&error); /* FIXME don't raise here */
6659 MonoObject *context = mono_runtime_capture_context (domain);
6660 /* we must capture the execution context from the original thread */
6662 MONO_OBJECT_SETREF (res, execution_context, context);
6663 /* note: result may be null if the flow is suppressed */
6666 res->data = (void **)data;
6667 MONO_OBJECT_SETREF (res, object_data, object_data);
6668 MONO_OBJECT_SETREF (res, async_state, state);
6670 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
6672 res->sync_completed = FALSE;
6673 res->completed = FALSE;
6679 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
6681 MONO_REQ_GC_UNSAFE_MODE;
6688 g_assert (ares->async_delegate);
6690 ac = (MonoAsyncCall*) ares->object_data;
6692 res = mono_runtime_delegate_invoke (ares->async_delegate, (void**) &ares->async_state, NULL);
6694 gpointer wait_event = NULL;
6696 ac->msg->exc = NULL;
6697 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args);
6698 MONO_OBJECT_SETREF (ac, res, res);
6700 mono_monitor_enter ((MonoObject*) ares);
6701 ares->completed = 1;
6703 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
6704 mono_monitor_exit ((MonoObject*) ares);
6706 if (wait_event != NULL)
6707 SetEvent (wait_event);
6709 if (ac->cb_method) {
6710 mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
6711 mono_error_raise_exception (&error);
6719 mono_message_init (MonoDomain *domain,
6720 MonoMethodMessage *this_obj,
6721 MonoReflectionMethod *method,
6722 MonoArray *out_args)
6724 MONO_REQ_GC_UNSAFE_MODE;
6726 static MonoClass *object_array_klass;
6727 static MonoClass *byte_array_klass;
6728 static MonoClass *string_array_klass;
6730 MonoMethodSignature *sig = mono_method_signature (method->method);
6737 if (!object_array_klass) {
6740 klass = mono_array_class_get (mono_defaults.byte_class, 1);
6742 byte_array_klass = klass;
6744 klass = mono_array_class_get (mono_defaults.string_class, 1);
6746 string_array_klass = klass;
6748 klass = mono_array_class_get (mono_defaults.object_class, 1);
6751 mono_atomic_store_release (&object_array_klass, klass);
6754 MONO_OBJECT_SETREF (this_obj, method, method);
6756 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), sig->param_count, &error);
6757 mono_error_raise_exception (&error); /* FIXME don't raise here */
6759 MONO_OBJECT_SETREF (this_obj, args, arr);
6761 arr = mono_array_new_specific_checked (mono_class_vtable (domain, byte_array_klass), sig->param_count, &error);
6762 mono_error_raise_exception (&error); /* FIXME don't raise here */
6764 MONO_OBJECT_SETREF (this_obj, arg_types, arr);
6766 this_obj->async_result = NULL;
6767 this_obj->call_type = CallType_Sync;
6769 names = g_new (char *, sig->param_count);
6770 mono_method_get_param_names (method->method, (const char **) names);
6772 arr = mono_array_new_specific_checked (mono_class_vtable (domain, string_array_klass), sig->param_count, &error);
6773 mono_error_raise_exception (&error); /* FIXME don't raise here */
6775 MONO_OBJECT_SETREF (this_obj, names, arr);
6777 for (i = 0; i < sig->param_count; i++) {
6778 name = mono_string_new (domain, names [i]);
6779 mono_array_setref (this_obj->names, i, name);
6783 for (i = 0, j = 0; i < sig->param_count; i++) {
6784 if (sig->params [i]->byref) {
6786 MonoObject* arg = (MonoObject *)mono_array_get (out_args, gpointer, j);
6787 mono_array_setref (this_obj->args, i, arg);
6791 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
6795 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
6798 mono_array_set (this_obj->arg_types, guint8, i, arg_type);
6802 #ifndef DISABLE_REMOTING
6804 * mono_remoting_invoke:
6805 * @real_proxy: pointer to a RealProxy object
6806 * @msg: The MonoMethodMessage to execute
6807 * @exc: used to store exceptions
6808 * @out_args: used to store output arguments
6810 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
6811 * IMessage interface and it is not trivial to extract results from there. So
6812 * we call an helper method PrivateInvoke instead of calling
6813 * RealProxy::Invoke() directly.
6815 * Returns: the result object.
6818 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
6819 MonoObject **exc, MonoArray **out_args)
6821 MONO_REQ_GC_UNSAFE_MODE;
6825 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
6828 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
6831 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
6833 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6834 real_proxy->vtable->domain->private_invoke_method = im;
6837 pa [0] = real_proxy;
6843 o = mono_runtime_try_invoke (im, NULL, pa, exc, &error);
6845 o = mono_runtime_invoke_checked (im, NULL, pa, &error);
6847 mono_error_raise_exception (&error); /* FIXME don't raise here */
6854 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
6855 MonoObject **exc, MonoArray **out_args)
6857 MONO_REQ_GC_UNSAFE_MODE;
6859 static MonoClass *object_array_klass;
6863 MonoMethodSignature *sig;
6866 int i, j, outarg_count = 0;
6868 #ifndef DISABLE_REMOTING
6869 if (target && mono_object_is_transparent_proxy (target)) {
6870 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
6871 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6872 target = tp->rp->unwrapped_server;
6874 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
6879 domain = mono_domain_get ();
6880 method = msg->method->method;
6881 sig = mono_method_signature (method);
6883 for (i = 0; i < sig->param_count; i++) {
6884 if (sig->params [i]->byref)
6888 if (!object_array_klass) {
6891 klass = mono_array_class_get (mono_defaults.object_class, 1);
6894 mono_memory_barrier ();
6895 object_array_klass = klass;
6898 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, &error);
6899 mono_error_raise_exception (&error); /* FIXME don't raise here */
6901 mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
6904 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
6906 for (i = 0, j = 0; i < sig->param_count; i++) {
6907 if (sig->params [i]->byref) {
6909 arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
6910 mono_array_setref (*out_args, j, arg);
6919 * mono_object_to_string:
6921 * @exc: Any exception thrown by ToString (). May be NULL.
6923 * Returns: the result of calling ToString () on an object.
6926 mono_object_to_string (MonoObject *obj, MonoObject **exc)
6928 MONO_REQ_GC_UNSAFE_MODE;
6930 static MonoMethod *to_string = NULL;
6939 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
6941 method = mono_object_get_virtual_method (obj, to_string);
6943 // Unbox value type if needed
6944 if (mono_class_is_valuetype (mono_method_get_class (method))) {
6945 target = mono_object_unbox (obj);
6949 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
6950 if (*exc == NULL && !mono_error_ok (&error))
6951 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
6953 mono_error_cleanup (&error);
6955 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
6956 mono_error_raise_exception (&error); /* FIXME don't raise here */
6963 * mono_print_unhandled_exception:
6964 * @exc: The exception
6966 * Prints the unhandled exception.
6969 mono_print_unhandled_exception (MonoObject *exc)
6971 MONO_REQ_GC_UNSAFE_MODE;
6974 char *message = (char*)"";
6975 gboolean free_message = FALSE;
6978 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
6979 message = g_strdup ("OutOfMemoryException");
6980 free_message = TRUE;
6981 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
6982 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
6983 free_message = TRUE;
6986 if (((MonoException*)exc)->native_trace_ips) {
6987 message = mono_exception_get_native_backtrace ((MonoException*)exc);
6988 free_message = TRUE;
6990 MonoObject *other_exc = NULL;
6991 str = mono_object_to_string (exc, &other_exc);
6993 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
6994 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
6996 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
6997 original_backtrace, nested_backtrace);
6999 g_free (original_backtrace);
7000 g_free (nested_backtrace);
7001 free_message = TRUE;
7003 message = mono_string_to_utf8_checked (str, &error);
7004 if (!mono_error_ok (&error)) {
7005 mono_error_cleanup (&error);
7006 message = (char *) "";
7008 free_message = TRUE;
7015 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
7016 * exc->vtable->klass->name, message);
7018 g_printerr ("\nUnhandled Exception:\n%s\n", message);
7025 * mono_delegate_ctor:
7026 * @this: pointer to an uninitialized delegate object
7027 * @target: target object
7028 * @addr: pointer to native code
7031 * Initialize a delegate and sets a specific method, not the one
7032 * associated with addr. This is useful when sharing generic code.
7033 * In that case addr will most probably not be associated with the
7034 * correct instantiation of the method.
7037 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method)
7039 MONO_REQ_GC_UNSAFE_MODE;
7041 MonoDelegate *delegate = (MonoDelegate *)this_obj;
7043 g_assert (this_obj);
7046 g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
7049 delegate->method = method;
7051 mono_stats.delegate_creations++;
7053 #ifndef DISABLE_REMOTING
7054 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
7056 method = mono_marshal_get_remoting_invoke (method);
7057 delegate->method_ptr = mono_compile_method (method);
7058 MONO_OBJECT_SETREF (delegate, target, target);
7062 delegate->method_ptr = addr;
7063 MONO_OBJECT_SETREF (delegate, target, target);
7066 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
7067 if (callbacks.init_delegate)
7068 callbacks.init_delegate (delegate);
7072 * mono_delegate_ctor:
7073 * @this: pointer to an uninitialized delegate object
7074 * @target: target object
7075 * @addr: pointer to native code
7077 * This is used to initialize a delegate.
7080 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr)
7082 MONO_REQ_GC_UNSAFE_MODE;
7084 MonoDomain *domain = mono_domain_get ();
7086 MonoMethod *method = NULL;
7090 ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
7092 if (!ji && domain != mono_get_root_domain ())
7093 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
7095 method = mono_jit_info_get_method (ji);
7096 g_assert (!method->klass->generic_container);
7099 mono_delegate_ctor_with_method (this_obj, target, addr, method);
7103 * mono_method_call_message_new:
7104 * @method: method to encapsulate
7105 * @params: parameters to the method
7106 * @invoke: optional, delegate invoke.
7107 * @cb: async callback delegate.
7108 * @state: state passed to the async callback.
7110 * Translates arguments pointers into a MonoMethodMessage.
7113 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
7114 MonoDelegate **cb, MonoObject **state)
7116 MONO_REQ_GC_UNSAFE_MODE;
7120 MonoDomain *domain = mono_domain_get ();
7121 MonoMethodSignature *sig = mono_method_signature (method);
7122 MonoMethodMessage *msg;
7125 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7126 mono_error_raise_exception (&error); /* FIXME don't raise here */
7129 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, &error);
7130 mono_error_raise_exception (&error); /* FIXME don't raise here */
7131 mono_message_init (domain, msg, rm, NULL);
7132 count = sig->param_count - 2;
7134 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, &error);
7135 mono_error_raise_exception (&error); /* FIXME don't raise here */
7136 mono_message_init (domain, msg, rm, NULL);
7137 count = sig->param_count;
7140 for (i = 0; i < count; i++) {
7145 if (sig->params [i]->byref)
7146 vpos = *((gpointer *)params [i]);
7150 klass = mono_class_from_mono_type (sig->params [i]);
7152 if (klass->valuetype)
7153 arg = mono_value_box (domain, klass, vpos);
7155 arg = *((MonoObject **)vpos);
7157 mono_array_setref (msg->args, i, arg);
7160 if (cb != NULL && state != NULL) {
7161 *cb = *((MonoDelegate **)params [i]);
7163 *state = *((MonoObject **)params [i]);
7170 * mono_method_return_message_restore:
7172 * Restore results from message based processing back to arguments pointers
7175 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
7177 MONO_REQ_GC_UNSAFE_MODE;
7179 MonoMethodSignature *sig = mono_method_signature (method);
7180 int i, j, type, size, out_len;
7182 if (out_args == NULL)
7184 out_len = mono_array_length (out_args);
7188 for (i = 0, j = 0; i < sig->param_count; i++) {
7189 MonoType *pt = sig->params [i];
7194 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
7196 arg = (char *)mono_array_get (out_args, gpointer, j);
7199 g_assert (type != MONO_TYPE_VOID);
7201 if (MONO_TYPE_IS_REFERENCE (pt)) {
7202 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
7205 MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
7206 size = mono_class_value_size (klass, NULL);
7207 if (klass->has_references)
7208 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
7210 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
7212 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
7213 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
7222 #ifndef DISABLE_REMOTING
7225 * mono_load_remote_field:
7226 * @this: pointer to an object
7227 * @klass: klass of the object containing @field
7228 * @field: the field to load
7229 * @res: a storage to store the result
7231 * This method is called by the runtime on attempts to load fields of
7232 * transparent proxy objects. @this points to such TP, @klass is the class of
7233 * the object containing @field. @res is a storage location which can be
7234 * used to store the result.
7236 * Returns: an address pointing to the value of field.
7239 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
7241 MONO_REQ_GC_UNSAFE_MODE;
7245 static MonoMethod *getter = NULL;
7246 MonoDomain *domain = mono_domain_get ();
7247 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7248 MonoClass *field_class;
7249 MonoMethodMessage *msg;
7250 MonoArray *out_args;
7254 g_assert (mono_object_is_transparent_proxy (this_obj));
7255 g_assert (res != NULL);
7257 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7258 mono_field_get_value (tp->rp->unwrapped_server, field, res);
7263 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
7265 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7268 field_class = mono_class_from_mono_type (field->type);
7270 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7271 mono_error_raise_exception (&error); /* FIXME don't raise here */
7272 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
7273 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, &error);
7274 mono_error_raise_exception (&error); /* FIXME don't raise here */
7275 mono_message_init (domain, msg, rm, out_args);
7277 full_name = mono_type_get_full_name (klass);
7278 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7279 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7282 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
7284 if (exc) mono_raise_exception ((MonoException *)exc);
7286 if (mono_array_length (out_args) == 0)
7289 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
7291 if (field_class->valuetype) {
7292 return ((char *)*res) + sizeof (MonoObject);
7298 * mono_load_remote_field_new:
7303 * Missing documentation.
7306 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
7308 MONO_REQ_GC_UNSAFE_MODE;
7312 static MonoMethod *getter = NULL;
7313 MonoDomain *domain = mono_domain_get ();
7314 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7315 MonoClass *field_class;
7316 MonoMethodMessage *msg;
7317 MonoArray *out_args;
7318 MonoObject *exc, *res;
7321 g_assert (mono_object_is_transparent_proxy (this_obj));
7323 field_class = mono_class_from_mono_type (field->type);
7325 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7327 if (field_class->valuetype) {
7328 res = mono_object_new_checked (domain, field_class, &error);
7329 mono_error_raise_exception (&error); /* FIXME don't raise here */
7330 val = ((gchar *) res) + sizeof (MonoObject);
7334 mono_field_get_value (tp->rp->unwrapped_server, field, val);
7339 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
7341 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7344 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7345 mono_error_raise_exception (&error); /* FIXME don't raise here */
7346 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
7348 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, &error);
7349 mono_error_raise_exception (&error); /* FIXME don't raise here */
7350 mono_message_init (domain, msg, rm, out_args);
7352 full_name = mono_type_get_full_name (klass);
7353 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7354 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7357 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
7359 if (exc) mono_raise_exception ((MonoException *)exc);
7361 if (mono_array_length (out_args) == 0)
7364 res = mono_array_get (out_args, MonoObject *, 0);
7370 * mono_store_remote_field:
7371 * @this_obj: pointer to an object
7372 * @klass: klass of the object containing @field
7373 * @field: the field to load
7374 * @val: the value/object to store
7376 * This method is called by the runtime on attempts to store fields of
7377 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
7378 * the object containing @field. @val is the new value to store in @field.
7381 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
7383 MONO_REQ_GC_UNSAFE_MODE;
7387 static MonoMethod *setter = NULL;
7388 MonoDomain *domain = mono_domain_get ();
7389 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7390 MonoClass *field_class;
7391 MonoMethodMessage *msg;
7392 MonoArray *out_args;
7397 g_assert (mono_object_is_transparent_proxy (this_obj));
7399 field_class = mono_class_from_mono_type (field->type);
7401 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7402 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
7403 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
7408 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
7410 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7413 if (field_class->valuetype)
7414 arg = mono_value_box (domain, field_class, val);
7416 arg = *((MonoObject **)val);
7419 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7420 mono_error_raise_exception (&error); /* FIXME don't raise here */
7421 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, setter, NULL, &error);
7422 mono_error_raise_exception (&error); /* FIXME don't raise here */
7423 mono_message_init (domain, msg, rm, NULL);
7425 full_name = mono_type_get_full_name (klass);
7426 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7427 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7428 mono_array_setref (msg->args, 2, arg);
7431 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
7433 if (exc) mono_raise_exception ((MonoException *)exc);
7437 * mono_store_remote_field_new:
7443 * Missing documentation
7446 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
7448 MONO_REQ_GC_UNSAFE_MODE;
7452 static MonoMethod *setter = NULL;
7453 MonoDomain *domain = mono_domain_get ();
7454 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7455 MonoClass *field_class;
7456 MonoMethodMessage *msg;
7457 MonoArray *out_args;
7461 g_assert (mono_object_is_transparent_proxy (this_obj));
7463 field_class = mono_class_from_mono_type (field->type);
7465 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7466 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
7467 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
7472 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
7474 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7477 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7478 mono_error_raise_exception (&error); /* FIXME don't raise here */
7479 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, setter, NULL, &error);
7480 mono_error_raise_exception (&error); /* FIXME don't raise here */
7481 mono_message_init (domain, msg, rm, NULL);
7483 full_name = mono_type_get_full_name (klass);
7484 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7485 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7486 mono_array_setref (msg->args, 2, arg);
7489 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
7491 if (exc) mono_raise_exception ((MonoException *)exc);
7496 * mono_create_ftnptr:
7498 * Given a function address, create a function descriptor for it.
7499 * This is only needed on some platforms.
7502 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
7504 return callbacks.create_ftnptr (domain, addr);
7508 * mono_get_addr_from_ftnptr:
7510 * Given a pointer to a function descriptor, return the function address.
7511 * This is only needed on some platforms.
7514 mono_get_addr_from_ftnptr (gpointer descr)
7516 return callbacks.get_addr_from_ftnptr (descr);
7520 * mono_string_chars:
7523 * Returns a pointer to the UCS16 characters stored in the MonoString
7526 mono_string_chars (MonoString *s)
7528 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
7534 * mono_string_length:
7537 * Returns the lenght in characters of the string
7540 mono_string_length (MonoString *s)
7542 MONO_REQ_GC_UNSAFE_MODE;
7548 * mono_array_length:
7549 * @array: a MonoArray*
7551 * Returns the total number of elements in the array. This works for
7552 * both vectors and multidimensional arrays.
7555 mono_array_length (MonoArray *array)
7557 MONO_REQ_GC_UNSAFE_MODE;
7559 return array->max_length;
7563 * mono_array_addr_with_size:
7564 * @array: a MonoArray*
7565 * @size: size of the array elements
7566 * @idx: index into the array
7568 * Use this function to obtain the address for the @idx item on the
7569 * @array containing elements of size @size.
7571 * This method performs no bounds checking or type checking.
7573 * Returns the address of the @idx element in the array.
7576 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
7578 MONO_REQ_GC_UNSAFE_MODE;
7580 return ((char*)(array)->vector) + size * idx;
7585 mono_glist_to_array (GList *list, MonoClass *eclass)
7587 MonoDomain *domain = mono_domain_get ();
7594 len = g_list_length (list);
7595 res = mono_array_new (domain, eclass, len);
7597 for (i = 0; list; list = list->next, i++)
7598 mono_array_set (res, gpointer, i, list->data);
7605 * The following section is purely to declare prototypes and
7606 * document the API, as these C files are processed by our
7612 * @array: array to alter
7613 * @element_type: A C type name, this macro will use the sizeof(type) to determine the element size
7614 * @index: index into the array
7615 * @value: value to set
7617 * Value Type version: This sets the @index's element of the @array
7618 * with elements of size sizeof(type) to the provided @value.
7620 * This macro does not attempt to perform type checking or bounds checking.
7622 * Use this to set value types in a `MonoArray`.
7624 void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
7629 * mono_array_setref:
7630 * @array: array to alter
7631 * @index: index into the array
7632 * @value: value to set
7634 * Reference Type version: This sets the @index's element of the
7635 * @array with elements of size sizeof(type) to the provided @value.
7637 * This macro does not attempt to perform type checking or bounds checking.
7639 * Use this to reference types in a `MonoArray`.
7641 void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
7647 * @array: array on which to operate on
7648 * @element_type: C element type (example: MonoString *, int, MonoObject *)
7649 * @index: index into the array
7651 * Use this macro to retrieve the @index element of an @array and
7652 * extract the value assuming that the elements of the array match
7653 * the provided type value.
7655 * This method can be used with both arrays holding value types and
7656 * reference types. For reference types, the @type parameter should
7657 * be a `MonoObject*` or any subclass of it, like `MonoString*`.
7659 * This macro does not attempt to perform type checking or bounds checking.
7661 * Returns: The element at the @index position in the @array.
7663 Type mono_array_get (MonoArray *array, Type element_type, uintptr_t index)