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 MonoTrampoline arch_create_jit_trampoline = default_trampoline;
544 static MonoJumpTrampoline arch_create_jump_trampoline = default_jump_trampoline;
545 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
546 static MonoImtThunkBuilder imt_thunk_builder;
547 static gboolean always_build_imt_thunks;
549 #if (MONO_IMT_SIZE > 32)
550 #error "MONO_IMT_SIZE cannot be larger than 32"
554 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
556 memcpy (&callbacks, cbs, sizeof (*cbs));
559 MonoRuntimeCallbacks*
560 mono_get_runtime_callbacks (void)
566 mono_install_trampoline (MonoTrampoline func)
568 arch_create_jit_trampoline = func? func: default_trampoline;
572 mono_install_jump_trampoline (MonoJumpTrampoline func)
574 arch_create_jump_trampoline = func? func: default_jump_trampoline;
577 #ifndef DISABLE_REMOTING
579 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
581 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
586 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
588 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
592 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
593 imt_thunk_builder = func;
597 mono_set_always_build_imt_thunks (gboolean value)
599 always_build_imt_thunks = value;
603 * mono_compile_method:
604 * @method: The method to compile.
606 * This JIT-compiles the method, and returns the pointer to the native code
610 mono_compile_method (MonoMethod *method)
615 MONO_REQ_GC_NEUTRAL_MODE
617 if (!callbacks.compile_method) {
618 g_error ("compile method called on uninitialized runtime");
621 res = callbacks.compile_method (method, &error);
622 if (!mono_error_ok (&error))
623 mono_error_raise_exception (&error);
628 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
630 MONO_REQ_GC_NEUTRAL_MODE
632 return arch_create_jump_trampoline (domain, method, add_sync_wrapper);
636 mono_runtime_create_delegate_trampoline (MonoClass *klass)
638 MONO_REQ_GC_NEUTRAL_MODE
640 return arch_create_delegate_trampoline (mono_domain_get (), klass);
643 static MonoFreeMethodFunc default_mono_free_method = NULL;
646 * mono_install_free_method:
647 * @func: pointer to the MonoFreeMethodFunc used to release a method
649 * This is an internal VM routine, it is used for the engines to
650 * register a handler to release the resources associated with a method.
652 * Methods are freed when no more references to the delegate that holds
656 mono_install_free_method (MonoFreeMethodFunc func)
658 default_mono_free_method = func;
662 * mono_runtime_free_method:
663 * @domain; domain where the method is hosted
664 * @method: method to release
666 * This routine is invoked to free the resources associated with
667 * a method that has been JIT compiled. This is used to discard
668 * methods that were used only temporarily (for example, used in marshalling)
672 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
674 MONO_REQ_GC_NEUTRAL_MODE
676 if (default_mono_free_method != NULL)
677 default_mono_free_method (domain, method);
679 mono_method_clear_object (domain, method);
681 mono_free_method (method);
685 * The vtables in the root appdomain are assumed to be reachable by other
686 * roots, and we don't use typed allocation in the other domains.
689 /* The sync block is no longer a GC pointer */
690 #define GC_HEADER_BITMAP (0)
692 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
695 compute_class_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
697 MONO_REQ_GC_NEUTRAL_MODE;
699 MonoClassField *field;
705 max_size = mono_class_data_size (klass) / sizeof (gpointer);
707 max_size = klass->instance_size / sizeof (gpointer);
708 if (max_size > size) {
709 g_assert (offset <= 0);
710 bitmap = (gsize *)g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
715 /*An Ephemeron cannot be marked by sgen*/
716 if (!static_fields && klass->image == mono_defaults.corlib && !strcmp ("Ephemeron", klass->name)) {
718 memset (bitmap, 0, size / 8);
723 for (p = klass; p != NULL; p = p->parent) {
724 gpointer iter = NULL;
725 while ((field = mono_class_get_fields (p, &iter))) {
729 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
731 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
734 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
737 /* FIXME: should not happen, flag as type load error */
738 if (field->type->byref)
741 if (static_fields && field->offset == -1)
745 pos = field->offset / sizeof (gpointer);
748 type = mono_type_get_underlying_type (field->type);
749 switch (type->type) {
752 case MONO_TYPE_FNPTR:
754 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
759 if (klass->image != mono_defaults.corlib)
762 case MONO_TYPE_STRING:
763 case MONO_TYPE_SZARRAY:
764 case MONO_TYPE_CLASS:
765 case MONO_TYPE_OBJECT:
766 case MONO_TYPE_ARRAY:
767 g_assert ((field->offset % sizeof(gpointer)) == 0);
769 g_assert (pos < size || pos <= max_size);
770 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
771 *max_set = MAX (*max_set, pos);
773 case MONO_TYPE_GENERICINST:
774 if (!mono_type_generic_inst_is_valuetype (type)) {
775 g_assert ((field->offset % sizeof(gpointer)) == 0);
777 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
778 *max_set = MAX (*max_set, pos);
783 case MONO_TYPE_VALUETYPE: {
784 MonoClass *fclass = mono_class_from_mono_type (field->type);
785 if (fclass->has_references) {
786 /* remove the object header */
787 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
801 case MONO_TYPE_BOOLEAN:
805 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
816 * mono_class_compute_bitmap:
818 * Mono internal function to compute a bitmap of reference fields in a class.
821 mono_class_compute_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
823 MONO_REQ_GC_NEUTRAL_MODE;
825 return compute_class_bitmap (klass, bitmap, size, offset, max_set, static_fields);
830 * similar to the above, but sets the bits in the bitmap for any non-ref field
831 * and ignores static fields
834 compute_class_non_ref_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset)
836 MonoClassField *field;
841 max_size = class->instance_size / sizeof (gpointer);
842 if (max_size >= size) {
843 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
846 for (p = class; p != NULL; p = p->parent) {
847 gpointer iter = NULL;
848 while ((field = mono_class_get_fields (p, &iter))) {
851 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
853 /* FIXME: should not happen, flag as type load error */
854 if (field->type->byref)
857 pos = field->offset / sizeof (gpointer);
860 type = mono_type_get_underlying_type (field->type);
861 switch (type->type) {
862 #if SIZEOF_VOID_P == 8
866 case MONO_TYPE_FNPTR:
871 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
872 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
873 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
876 #if SIZEOF_VOID_P == 4
880 case MONO_TYPE_FNPTR:
885 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
886 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
887 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
893 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
894 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
895 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
898 case MONO_TYPE_BOOLEAN:
901 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
903 case MONO_TYPE_STRING:
904 case MONO_TYPE_SZARRAY:
905 case MONO_TYPE_CLASS:
906 case MONO_TYPE_OBJECT:
907 case MONO_TYPE_ARRAY:
909 case MONO_TYPE_GENERICINST:
910 if (!mono_type_generic_inst_is_valuetype (type)) {
915 case MONO_TYPE_VALUETYPE: {
916 MonoClass *fclass = mono_class_from_mono_type (field->type);
917 /* remove the object header */
918 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
922 g_assert_not_reached ();
931 * mono_class_insecure_overlapping:
932 * check if a class with explicit layout has references and non-references
933 * fields overlapping.
935 * Returns: TRUE if it is insecure to load the type.
938 mono_class_insecure_overlapping (MonoClass *klass)
942 gsize default_bitmap [4] = {0};
944 gsize default_nrbitmap [4] = {0};
945 int i, insecure = FALSE;
948 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
949 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
951 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
952 int idx = i % (sizeof (bitmap [0]) * 8);
953 if (bitmap [idx] & nrbitmap [idx]) {
958 if (bitmap != default_bitmap)
960 if (nrbitmap != default_nrbitmap)
963 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
971 ves_icall_string_alloc (int length)
974 MonoString *str = mono_string_new_size_checked (mono_domain_get (), length, &error);
975 mono_error_raise_exception (&error);
981 mono_class_compute_gc_descriptor (MonoClass *klass)
983 MONO_REQ_GC_NEUTRAL_MODE;
987 gsize default_bitmap [4] = {0};
988 static gboolean gcj_inited = FALSE;
993 mono_register_jit_icall (ves_icall_object_new_fast, "ves_icall_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
994 mono_register_jit_icall (ves_icall_string_alloc, "ves_icall_string_alloc", mono_create_icall_signature ("object int"), FALSE);
997 mono_loader_unlock ();
1001 mono_class_init (klass);
1003 if (klass->gc_descr_inited)
1006 klass->gc_descr_inited = TRUE;
1007 klass->gc_descr = MONO_GC_DESCRIPTOR_NULL;
1009 bitmap = default_bitmap;
1010 if (klass == mono_defaults.string_class) {
1011 klass->gc_descr = mono_gc_make_descr_for_string (bitmap, 2);
1012 } else if (klass->rank) {
1013 mono_class_compute_gc_descriptor (klass->element_class);
1014 if (MONO_TYPE_IS_REFERENCE (&klass->element_class->byval_arg)) {
1016 klass->gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
1017 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1018 class->name_space, class->name);*/
1020 /* remove the object header */
1021 bitmap = compute_class_bitmap (klass->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
1022 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));
1023 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1024 class->name_space, class->name);*/
1025 if (bitmap != default_bitmap)
1029 /*static int count = 0;
1032 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1033 klass->gc_descr = mono_gc_make_descr_for_object (bitmap, max_set + 1, klass->instance_size);
1035 if (class->gc_descr == MONO_GC_DESCRIPTOR_NULL)
1036 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
1038 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
1039 if (bitmap != default_bitmap)
1045 * field_is_special_static:
1046 * @fklass: The MonoClass to look up.
1047 * @field: The MonoClassField describing the field.
1049 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1050 * SPECIAL_STATIC_NONE otherwise.
1053 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1055 MONO_REQ_GC_NEUTRAL_MODE;
1057 MonoCustomAttrInfo *ainfo;
1059 ainfo = mono_custom_attrs_from_field (fklass, field);
1062 for (i = 0; i < ainfo->num_attrs; ++i) {
1063 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1064 if (klass->image == mono_defaults.corlib) {
1065 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1066 mono_custom_attrs_free (ainfo);
1067 return SPECIAL_STATIC_THREAD;
1069 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1070 mono_custom_attrs_free (ainfo);
1071 return SPECIAL_STATIC_CONTEXT;
1075 mono_custom_attrs_free (ainfo);
1076 return SPECIAL_STATIC_NONE;
1079 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1080 #define mix(a,b,c) { \
1081 a -= c; a ^= rot(c, 4); c += b; \
1082 b -= a; b ^= rot(a, 6); a += c; \
1083 c -= b; c ^= rot(b, 8); b += a; \
1084 a -= c; a ^= rot(c,16); c += b; \
1085 b -= a; b ^= rot(a,19); a += c; \
1086 c -= b; c ^= rot(b, 4); b += a; \
1088 #define final(a,b,c) { \
1089 c ^= b; c -= rot(b,14); \
1090 a ^= c; a -= rot(c,11); \
1091 b ^= a; b -= rot(a,25); \
1092 c ^= b; c -= rot(b,16); \
1093 a ^= c; a -= rot(c,4); \
1094 b ^= a; b -= rot(a,14); \
1095 c ^= b; c -= rot(b,24); \
1099 * mono_method_get_imt_slot:
1101 * The IMT slot is embedded into AOTed code, so this must return the same value
1102 * for the same method across all executions. This means:
1103 * - pointers shouldn't be used as hash values.
1104 * - mono_metadata_str_hash () should be used for hashing strings.
1107 mono_method_get_imt_slot (MonoMethod *method)
1109 MONO_REQ_GC_NEUTRAL_MODE;
1111 MonoMethodSignature *sig;
1113 guint32 *hashes_start, *hashes;
1117 /* This can be used to stress tests the collision code */
1121 * We do this to simplify generic sharing. It will hurt
1122 * performance in cases where a class implements two different
1123 * instantiations of the same generic interface.
1124 * The code in build_imt_slots () depends on this.
1126 if (method->is_inflated)
1127 method = ((MonoMethodInflated*)method)->declaring;
1129 sig = mono_method_signature (method);
1130 hashes_count = sig->param_count + 4;
1131 hashes_start = (guint32 *)malloc (hashes_count * sizeof (guint32));
1132 hashes = hashes_start;
1134 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1135 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1136 method->klass->name_space, method->klass->name, method->name);
1139 /* Initialize hashes */
1140 hashes [0] = mono_metadata_str_hash (method->klass->name);
1141 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1142 hashes [2] = mono_metadata_str_hash (method->name);
1143 hashes [3] = mono_metadata_type_hash (sig->ret);
1144 for (i = 0; i < sig->param_count; i++) {
1145 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1148 /* Setup internal state */
1149 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1151 /* Handle most of the hashes */
1152 while (hashes_count > 3) {
1161 /* Handle the last 3 hashes (all the case statements fall through) */
1162 switch (hashes_count) {
1163 case 3 : c += hashes [2];
1164 case 2 : b += hashes [1];
1165 case 1 : a += hashes [0];
1167 case 0: /* nothing left to add */
1171 free (hashes_start);
1172 /* Report the result */
1173 return c % MONO_IMT_SIZE;
1182 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1183 MONO_REQ_GC_NEUTRAL_MODE;
1185 guint32 imt_slot = mono_method_get_imt_slot (method);
1186 MonoImtBuilderEntry *entry;
1188 if (slot_num >= 0 && imt_slot != slot_num) {
1189 /* we build just a single imt slot and this is not it */
1193 entry = (MonoImtBuilderEntry *)g_malloc0 (sizeof (MonoImtBuilderEntry));
1194 entry->key = method;
1195 entry->value.vtable_slot = vtable_slot;
1196 entry->next = imt_builder [imt_slot];
1197 if (imt_builder [imt_slot] != NULL) {
1198 entry->children = imt_builder [imt_slot]->children + 1;
1199 if (entry->children == 1) {
1200 mono_stats.imt_slots_with_collisions++;
1201 *imt_collisions_bitmap |= (1 << imt_slot);
1204 entry->children = 0;
1205 mono_stats.imt_used_slots++;
1207 imt_builder [imt_slot] = entry;
1210 char *method_name = mono_method_full_name (method, TRUE);
1211 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1212 method, method_name, imt_slot, vtable_slot, entry->children);
1213 g_free (method_name);
1220 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1222 MonoMethod *method = e->key;
1223 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1227 method->klass->name_space,
1228 method->klass->name,
1231 printf (" * %s: NULL\n", message);
1237 compare_imt_builder_entries (const void *p1, const void *p2) {
1238 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1239 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1241 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1245 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1247 MONO_REQ_GC_NEUTRAL_MODE;
1249 int count = end - start;
1250 int chunk_start = out_array->len;
1253 for (i = start; i < end; ++i) {
1254 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1255 item->key = sorted_array [i]->key;
1256 item->value = sorted_array [i]->value;
1257 item->has_target_code = sorted_array [i]->has_target_code;
1258 item->is_equals = TRUE;
1260 item->check_target_idx = out_array->len + 1;
1262 item->check_target_idx = 0;
1263 g_ptr_array_add (out_array, item);
1266 int middle = start + count / 2;
1267 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1269 item->key = sorted_array [middle]->key;
1270 item->is_equals = FALSE;
1271 g_ptr_array_add (out_array, item);
1272 imt_emit_ir (sorted_array, start, middle, out_array);
1273 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1279 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1280 MONO_REQ_GC_NEUTRAL_MODE;
1282 int number_of_entries = entries->children + 1;
1283 MonoImtBuilderEntry **sorted_array = (MonoImtBuilderEntry **)malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1284 GPtrArray *result = g_ptr_array_new ();
1285 MonoImtBuilderEntry *current_entry;
1288 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1289 sorted_array [i] = current_entry;
1291 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1293 /*for (i = 0; i < number_of_entries; i++) {
1294 print_imt_entry (" sorted array:", sorted_array [i], i);
1297 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1299 free (sorted_array);
1304 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1306 MONO_REQ_GC_NEUTRAL_MODE;
1308 if (imt_builder_entry != NULL) {
1309 if (imt_builder_entry->children == 0 && !fail_tramp && !always_build_imt_thunks) {
1310 /* No collision, return the vtable slot contents */
1311 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1313 /* Collision, build the thunk */
1314 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1317 result = imt_thunk_builder (vtable, domain,
1318 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1319 for (i = 0; i < imt_ir->len; ++i)
1320 g_free (g_ptr_array_index (imt_ir, i));
1321 g_ptr_array_free (imt_ir, TRUE);
1333 static MonoImtBuilderEntry*
1334 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1337 * LOCKING: requires the loader and domain locks.
1341 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1343 MONO_REQ_GC_NEUTRAL_MODE;
1347 guint32 imt_collisions_bitmap = 0;
1348 MonoImtBuilderEntry **imt_builder = (MonoImtBuilderEntry **)calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1349 int method_count = 0;
1350 gboolean record_method_count_for_max_collisions = FALSE;
1351 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1354 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1356 for (i = 0; i < klass->interface_offsets_count; ++i) {
1357 MonoClass *iface = klass->interfaces_packed [i];
1358 int interface_offset = klass->interface_offsets_packed [i];
1359 int method_slot_in_interface, vt_slot;
1361 if (mono_class_has_variant_generic_params (iface))
1362 has_variant_iface = TRUE;
1364 mono_class_setup_methods (iface);
1365 vt_slot = interface_offset;
1366 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1369 if (slot_num >= 0 && iface->is_inflated) {
1371 * The imt slot of the method is the same as for its declaring method,
1372 * see the comment in mono_method_get_imt_slot (), so we can
1373 * avoid inflating methods which will be discarded by
1374 * add_imt_builder_entry anyway.
1376 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1377 if (mono_method_get_imt_slot (method) != slot_num) {
1382 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1383 if (method->is_generic) {
1384 has_generic_virtual = TRUE;
1389 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1390 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1395 if (extra_interfaces) {
1396 int interface_offset = klass->vtable_size;
1398 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1399 MonoClass* iface = (MonoClass *)list_item->data;
1400 int method_slot_in_interface;
1401 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1402 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1404 if (method->is_generic)
1405 has_generic_virtual = TRUE;
1406 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1408 interface_offset += iface->method.count;
1411 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1412 /* overwrite the imt slot only if we're building all the entries or if
1413 * we're building this specific one
1415 if (slot_num < 0 || i == slot_num) {
1416 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1419 if (imt_builder [i]) {
1420 MonoImtBuilderEntry *entry;
1422 /* Link entries with imt_builder [i] */
1423 for (entry = entries; entry->next; entry = entry->next) {
1425 MonoMethod *method = (MonoMethod*)entry->key;
1426 char *method_name = mono_method_full_name (method, TRUE);
1427 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1428 g_free (method_name);
1431 entry->next = imt_builder [i];
1432 entries->children += imt_builder [i]->children + 1;
1434 imt_builder [i] = entries;
1437 if (has_generic_virtual || has_variant_iface) {
1439 * There might be collisions later when the the thunk is expanded.
1441 imt_collisions_bitmap |= (1 << i);
1444 * The IMT thunk might be called with an instance of one of the
1445 * generic virtual methods, so has to fallback to the IMT trampoline.
1447 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline (vt, i));
1449 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1452 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1456 if (imt_builder [i] != NULL) {
1457 int methods_in_slot = imt_builder [i]->children + 1;
1458 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1459 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1460 record_method_count_for_max_collisions = TRUE;
1462 method_count += methods_in_slot;
1466 mono_stats.imt_number_of_methods += method_count;
1467 if (record_method_count_for_max_collisions) {
1468 mono_stats.imt_method_count_when_max_collisions = method_count;
1471 for (i = 0; i < MONO_IMT_SIZE; i++) {
1472 MonoImtBuilderEntry* entry = imt_builder [i];
1473 while (entry != NULL) {
1474 MonoImtBuilderEntry* next = entry->next;
1480 /* we OR the bitmap since we may build just a single imt slot at a time */
1481 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1485 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1486 MONO_REQ_GC_NEUTRAL_MODE;
1488 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1492 * mono_vtable_build_imt_slot:
1493 * @vtable: virtual object table struct
1494 * @imt_slot: slot in the IMT table
1496 * Fill the given @imt_slot in the IMT table of @vtable with
1497 * a trampoline or a thunk for the case of collisions.
1498 * This is part of the internal mono API.
1500 * LOCKING: Take the domain lock.
1503 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1505 MONO_REQ_GC_NEUTRAL_MODE;
1507 gpointer *imt = (gpointer*)vtable;
1508 imt -= MONO_IMT_SIZE;
1509 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1511 /* no support for extra interfaces: the proxy objects will need
1512 * to build the complete IMT
1513 * Update and heck needs to ahppen inside the proper domain lock, as all
1514 * the changes made to a MonoVTable.
1516 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1517 mono_domain_lock (vtable->domain);
1518 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1519 if (!callbacks.imt_entry_inited (vtable, imt_slot))
1520 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1521 mono_domain_unlock (vtable->domain);
1522 mono_loader_unlock ();
1527 * The first two free list entries both belong to the wait list: The
1528 * first entry is the pointer to the head of the list and the second
1529 * entry points to the last element. That way appending and removing
1530 * the first element are both O(1) operations.
1532 #ifdef MONO_SMALL_CONFIG
1533 #define NUM_FREE_LISTS 6
1535 #define NUM_FREE_LISTS 12
1537 #define FIRST_FREE_LIST_SIZE 64
1538 #define MAX_WAIT_LENGTH 50
1539 #define THUNK_THRESHOLD 10
1542 * LOCKING: The domain lock must be held.
1545 init_thunk_free_lists (MonoDomain *domain)
1547 MONO_REQ_GC_NEUTRAL_MODE;
1549 if (domain->thunk_free_lists)
1551 domain->thunk_free_lists = (MonoThunkFreeList **)mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1555 list_index_for_size (int item_size)
1558 int size = FIRST_FREE_LIST_SIZE;
1560 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1569 * mono_method_alloc_generic_virtual_thunk:
1571 * @size: size in bytes
1573 * Allocs size bytes to be used for the code of a generic virtual
1574 * thunk. It's either allocated from the domain's code manager or
1575 * reused from a previously invalidated piece.
1577 * LOCKING: The domain lock must be held.
1580 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1582 MONO_REQ_GC_NEUTRAL_MODE;
1584 static gboolean inited = FALSE;
1585 static int generic_virtual_thunks_size = 0;
1589 MonoThunkFreeList **l;
1591 init_thunk_free_lists (domain);
1593 size += sizeof (guint32);
1594 if (size < sizeof (MonoThunkFreeList))
1595 size = sizeof (MonoThunkFreeList);
1597 i = list_index_for_size (size);
1598 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1599 if ((*l)->size >= size) {
1600 MonoThunkFreeList *item = *l;
1602 return ((guint32*)item) + 1;
1606 /* no suitable item found - search lists of larger sizes */
1607 while (++i < NUM_FREE_LISTS) {
1608 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1611 g_assert (item->size > size);
1612 domain->thunk_free_lists [i] = item->next;
1613 return ((guint32*)item) + 1;
1616 /* still nothing found - allocate it */
1618 mono_counters_register ("Generic virtual thunk bytes",
1619 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1622 generic_virtual_thunks_size += size;
1624 p = (guint32 *)mono_domain_code_reserve (domain, size);
1627 mono_domain_lock (domain);
1628 if (!domain->generic_virtual_thunks)
1629 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1630 g_hash_table_insert (domain->generic_virtual_thunks, p, p);
1631 mono_domain_unlock (domain);
1637 * LOCKING: The domain lock must be held.
1640 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1642 MONO_REQ_GC_NEUTRAL_MODE;
1644 guint32 *p = (guint32 *)code;
1645 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1646 gboolean found = FALSE;
1648 mono_domain_lock (domain);
1649 if (!domain->generic_virtual_thunks)
1650 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1651 if (g_hash_table_lookup (domain->generic_virtual_thunks, l))
1653 mono_domain_unlock (domain);
1656 /* Not allocated by mono_method_alloc_generic_virtual_thunk (), i.e. AOT */
1658 init_thunk_free_lists (domain);
1660 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1661 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1662 int length = item->length;
1665 /* unlink the first item from the wait list */
1666 domain->thunk_free_lists [0] = item->next;
1667 domain->thunk_free_lists [0]->length = length - 1;
1669 i = list_index_for_size (item->size);
1671 /* put it in the free list */
1672 item->next = domain->thunk_free_lists [i];
1673 domain->thunk_free_lists [i] = item;
1677 if (domain->thunk_free_lists [1]) {
1678 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1679 domain->thunk_free_lists [0]->length++;
1681 g_assert (!domain->thunk_free_lists [0]);
1683 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1684 domain->thunk_free_lists [0]->length = 1;
1688 typedef struct _GenericVirtualCase {
1692 struct _GenericVirtualCase *next;
1693 } GenericVirtualCase;
1696 * get_generic_virtual_entries:
1698 * Return IMT entries for the generic virtual method instances and
1699 * variant interface methods for vtable slot
1702 static MonoImtBuilderEntry*
1703 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1705 MONO_REQ_GC_NEUTRAL_MODE;
1707 GenericVirtualCase *list;
1708 MonoImtBuilderEntry *entries;
1710 mono_domain_lock (domain);
1711 if (!domain->generic_virtual_cases)
1712 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1714 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1717 for (; list; list = list->next) {
1718 MonoImtBuilderEntry *entry;
1720 if (list->count < THUNK_THRESHOLD)
1723 entry = g_new0 (MonoImtBuilderEntry, 1);
1724 entry->key = list->method;
1725 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1726 entry->has_target_code = 1;
1728 entry->children = entries->children + 1;
1729 entry->next = entries;
1733 mono_domain_unlock (domain);
1735 /* FIXME: Leaking memory ? */
1740 * mono_method_add_generic_virtual_invocation:
1742 * @vtable_slot: pointer to the vtable slot
1743 * @method: the inflated generic virtual method
1744 * @code: the method's code
1746 * Registers a call via unmanaged code to a generic virtual method
1747 * instantiation or variant interface method. If the number of calls reaches a threshold
1748 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1749 * virtual method thunk.
1752 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1753 gpointer *vtable_slot,
1754 MonoMethod *method, gpointer code)
1756 MONO_REQ_GC_NEUTRAL_MODE;
1758 static gboolean inited = FALSE;
1759 static int num_added = 0;
1761 GenericVirtualCase *gvc, *list;
1762 MonoImtBuilderEntry *entries;
1766 mono_domain_lock (domain);
1767 if (!domain->generic_virtual_cases)
1768 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1770 /* Check whether the case was already added */
1771 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1774 if (gvc->method == method)
1779 /* If not found, make a new one */
1781 gvc = (GenericVirtualCase *)mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1782 gvc->method = method;
1785 gvc->next = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1787 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1790 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1796 if (++gvc->count == THUNK_THRESHOLD) {
1797 gpointer *old_thunk = (void **)*vtable_slot;
1798 gpointer vtable_trampoline = NULL;
1799 gpointer imt_trampoline = NULL;
1801 if ((gpointer)vtable_slot < (gpointer)vtable) {
1802 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1803 int imt_slot = MONO_IMT_SIZE + displacement;
1805 /* Force the rebuild of the thunk at the next call */
1806 imt_trampoline = callbacks.get_imt_trampoline (vtable, imt_slot);
1807 *vtable_slot = imt_trampoline;
1809 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline (vtable, (gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1811 entries = get_generic_virtual_entries (domain, vtable_slot);
1813 sorted = imt_sort_slot_entries (entries);
1815 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1819 MonoImtBuilderEntry *next = entries->next;
1824 for (i = 0; i < sorted->len; ++i)
1825 g_free (g_ptr_array_index (sorted, i));
1826 g_ptr_array_free (sorted, TRUE);
1829 #ifndef __native_client__
1830 /* We don't re-use any thunks as there is a lot of overhead */
1831 /* to deleting and re-using code in Native Client. */
1832 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1833 invalidate_generic_virtual_thunk (domain, old_thunk);
1837 mono_domain_unlock (domain);
1840 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, gboolean raise_on_error);
1843 * mono_class_vtable:
1844 * @domain: the application domain
1845 * @class: the class to initialize
1847 * VTables are domain specific because we create domain specific code, and
1848 * they contain the domain specific static class data.
1849 * On failure, NULL is returned, and class->exception_type is set.
1852 mono_class_vtable (MonoDomain *domain, MonoClass *klass)
1854 return mono_class_vtable_full (domain, klass, FALSE);
1858 * mono_class_vtable_full:
1859 * @domain: the application domain
1860 * @class: the class to initialize
1861 * @raise_on_error if an exception should be raised on failure or not
1863 * VTables are domain specific because we create domain specific code, and
1864 * they contain the domain specific static class data.
1867 mono_class_vtable_full (MonoDomain *domain, MonoClass *klass, gboolean raise_on_error)
1869 MONO_REQ_GC_UNSAFE_MODE;
1871 MonoClassRuntimeInfo *runtime_info;
1875 if (klass->exception_type) {
1877 mono_raise_exception (mono_class_get_exception_for_failure (klass));
1881 /* this check can be inlined in jitted code, too */
1882 runtime_info = klass->runtime_info;
1883 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1884 return runtime_info->domain_vtables [domain->domain_id];
1885 return mono_class_create_runtime_vtable (domain, klass, raise_on_error);
1889 * mono_class_try_get_vtable:
1890 * @domain: the application domain
1891 * @class: the class to initialize
1893 * This function tries to get the associated vtable from @class if
1894 * it was already created.
1897 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *klass)
1899 MONO_REQ_GC_NEUTRAL_MODE;
1901 MonoClassRuntimeInfo *runtime_info;
1905 runtime_info = klass->runtime_info;
1906 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1907 return runtime_info->domain_vtables [domain->domain_id];
1912 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1914 MONO_REQ_GC_NEUTRAL_MODE;
1916 size_t alloc_offset;
1919 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1920 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1921 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1923 if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1924 g_assert ((imt_table_bytes & 7) == 4);
1931 return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1935 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, gboolean raise_on_error)
1937 MONO_REQ_GC_UNSAFE_MODE;
1941 MonoClassRuntimeInfo *runtime_info, *old_info;
1942 MonoClassField *field;
1944 int i, vtable_slots;
1945 size_t imt_table_bytes;
1947 guint32 vtable_size, class_size;
1949 gpointer *interface_offsets;
1951 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1952 mono_domain_lock (domain);
1953 runtime_info = klass->runtime_info;
1954 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1955 mono_domain_unlock (domain);
1956 mono_loader_unlock ();
1957 return runtime_info->domain_vtables [domain->domain_id];
1959 if (!klass->inited || klass->exception_type) {
1960 if (!mono_class_init (klass) || klass->exception_type) {
1961 mono_domain_unlock (domain);
1962 mono_loader_unlock ();
1964 mono_raise_exception (mono_class_get_exception_for_failure (klass));
1969 /* Array types require that their element type be valid*/
1970 if (klass->byval_arg.type == MONO_TYPE_ARRAY || klass->byval_arg.type == MONO_TYPE_SZARRAY) {
1971 MonoClass *element_class = klass->element_class;
1972 if (!element_class->inited)
1973 mono_class_init (element_class);
1975 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1976 if (element_class->exception_type == MONO_EXCEPTION_NONE && !element_class->vtable_size)
1977 mono_class_setup_vtable (element_class);
1979 if (element_class->exception_type != MONO_EXCEPTION_NONE) {
1980 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1981 if (klass->exception_type == MONO_EXCEPTION_NONE)
1982 mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
1983 mono_domain_unlock (domain);
1984 mono_loader_unlock ();
1986 mono_raise_exception (mono_class_get_exception_for_failure (klass));
1992 * For some classes, mono_class_init () already computed klass->vtable_size, and
1993 * that is all that is needed because of the vtable trampolines.
1995 if (!klass->vtable_size)
1996 mono_class_setup_vtable (klass);
1998 if (klass->generic_class && !klass->vtable)
1999 mono_class_check_vtable_constraints (klass, NULL);
2001 /* Initialize klass->has_finalize */
2002 mono_class_has_finalizer (klass);
2004 if (klass->exception_type) {
2005 mono_domain_unlock (domain);
2006 mono_loader_unlock ();
2008 mono_raise_exception (mono_class_get_exception_for_failure (klass));
2012 vtable_slots = klass->vtable_size;
2013 /* we add an additional vtable slot to store the pointer to static field data only when needed */
2014 class_size = mono_class_data_size (klass);
2018 if (klass->interface_offsets_count) {
2019 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
2020 mono_stats.imt_number_of_tables++;
2021 mono_stats.imt_tables_size += imt_table_bytes;
2023 imt_table_bytes = 0;
2026 vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
2028 mono_stats.used_class_count++;
2029 mono_stats.class_vtable_size += vtable_size;
2031 interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
2032 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2033 g_assert (!((gsize)vt & 7));
2036 vt->rank = klass->rank;
2037 vt->domain = domain;
2039 mono_class_compute_gc_descriptor (klass);
2041 * We can't use typed allocation in the non-root domains, since the
2042 * collector needs the GC descriptor stored in the vtable even after
2043 * the mempool containing the vtable is destroyed when the domain is
2044 * unloaded. An alternative might be to allocate vtables in the GC
2045 * heap, but this does not seem to work (it leads to crashes inside
2046 * libgc). If that approach is tried, two gc descriptors need to be
2047 * allocated for each class: one for the root domain, and one for all
2048 * other domains. The second descriptor should contain a bit for the
2049 * vtable field in MonoObject, since we can no longer assume the
2050 * vtable is reachable by other roots after the appdomain is unloaded.
2052 #ifdef HAVE_BOEHM_GC
2053 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
2054 vt->gc_descr = MONO_GC_DESCRIPTOR_NULL;
2057 vt->gc_descr = klass->gc_descr;
2059 gc_bits = mono_gc_get_vtable_bits (klass);
2060 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
2062 vt->gc_bits = gc_bits;
2065 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
2066 if (klass->has_static_refs) {
2067 MonoGCDescriptor statics_gc_descr;
2069 gsize default_bitmap [4] = {0};
2072 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
2073 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], klass->name_space, klass->name, class_size);*/
2074 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
2075 vt->vtable [klass->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr, MONO_ROOT_SOURCE_STATIC, "managed static variables");
2076 mono_domain_add_class_static_data (domain, klass, vt->vtable [klass->vtable_size], NULL);
2077 if (bitmap != default_bitmap)
2080 vt->vtable [klass->vtable_size] = mono_domain_alloc0 (domain, class_size);
2082 vt->has_static_fields = TRUE;
2083 mono_stats.class_static_data_size += class_size;
2087 while ((field = mono_class_get_fields (klass, &iter))) {
2088 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2090 if (mono_field_is_deleted (field))
2092 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2093 gint32 special_static = klass->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (klass, field);
2094 if (special_static != SPECIAL_STATIC_NONE) {
2095 guint32 size, offset;
2097 gsize default_bitmap [4] = {0};
2102 if (mono_type_is_reference (field->type)) {
2103 default_bitmap [0] = 1;
2105 bitmap = default_bitmap;
2106 } else if (mono_type_is_struct (field->type)) {
2107 fclass = mono_class_from_mono_type (field->type);
2108 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
2109 numbits = max_set + 1;
2111 default_bitmap [0] = 0;
2113 bitmap = default_bitmap;
2115 size = mono_type_size (field->type, &align);
2116 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
2117 if (!domain->special_static_fields)
2118 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2119 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2120 if (bitmap != default_bitmap)
2123 * This marks the field as special static to speed up the
2124 * checks in mono_field_static_get/set_value ().
2130 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2131 MonoClass *fklass = mono_class_from_mono_type (field->type);
2132 const char *data = mono_field_get_data (field);
2134 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2135 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2136 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2139 if (fklass->valuetype) {
2140 memcpy (t, data, mono_class_value_size (fklass, NULL));
2142 /* it's a pointer type: add check */
2143 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2150 vt->max_interface_id = klass->max_interface_id;
2151 vt->interface_bitmap = klass->interface_bitmap;
2153 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2154 // class->name, klass->interface_offsets_count);
2156 /* Initialize vtable */
2157 if (callbacks.get_vtable_trampoline) {
2158 // This also covers the AOT case
2159 for (i = 0; i < klass->vtable_size; ++i) {
2160 vt->vtable [i] = callbacks.get_vtable_trampoline (vt, i);
2163 mono_class_setup_vtable (klass);
2165 for (i = 0; i < klass->vtable_size; ++i) {
2168 if ((cm = klass->vtable [i]))
2169 vt->vtable [i] = arch_create_jit_trampoline (cm);
2173 if (imt_table_bytes) {
2174 /* Now that the vtable is full, we can actually fill up the IMT */
2175 for (i = 0; i < MONO_IMT_SIZE; ++i)
2176 interface_offsets [i] = callbacks.get_imt_trampoline (vt, i);
2180 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2181 * re-acquire them and check if another thread has created the vtable in the meantime.
2183 /* Special case System.MonoType to avoid infinite recursion */
2184 if (klass != mono_defaults.monotype_class) {
2185 /*FIXME check for OOM*/
2186 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, &error);
2187 mono_error_raise_exception (&error); /* FIXME don't raise here */
2189 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.monotype_class)
2190 /* This is unregistered in
2191 unregister_vtable_reflection_type() in
2193 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2196 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (klass));
2198 /* class_vtable_array keeps an array of created vtables
2200 g_ptr_array_add (domain->class_vtable_array, vt);
2201 /* klass->runtime_info is protected by the loader lock, both when
2202 * it it enlarged and when it is stored info.
2206 * Store the vtable in klass->runtime_info.
2207 * klass->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2209 mono_memory_barrier ();
2211 old_info = klass->runtime_info;
2212 if (old_info && old_info->max_domain >= domain->domain_id) {
2213 /* someone already created a large enough runtime info */
2214 old_info->domain_vtables [domain->domain_id] = vt;
2216 int new_size = domain->domain_id;
2218 new_size = MAX (new_size, old_info->max_domain);
2220 /* make the new size a power of two */
2222 while (new_size > i)
2225 /* this is a bounded memory retention issue: may want to
2226 * handle it differently when we'll have a rcu-like system.
2228 runtime_info = (MonoClassRuntimeInfo *)mono_image_alloc0 (klass->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2229 runtime_info->max_domain = new_size - 1;
2230 /* copy the stuff from the older info */
2232 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2234 runtime_info->domain_vtables [domain->domain_id] = vt;
2236 mono_memory_barrier ();
2237 klass->runtime_info = runtime_info;
2240 if (klass == mono_defaults.monotype_class) {
2241 /*FIXME check for OOM*/
2242 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, &error);
2243 mono_error_raise_exception (&error); /* FIXME don't raise here */
2245 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.monotype_class)
2246 /* This is unregistered in
2247 unregister_vtable_reflection_type() in
2249 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2252 mono_domain_unlock (domain);
2253 mono_loader_unlock ();
2255 /* make sure the parent is initialized */
2256 /*FIXME shouldn't this fail the current type?*/
2258 mono_class_vtable_full (domain, klass->parent, raise_on_error);
2263 #ifndef DISABLE_REMOTING
2265 * mono_class_proxy_vtable:
2266 * @domain: the application domain
2267 * @remove_class: the remote class
2269 * Creates a vtable for transparent proxies. It is basically
2270 * a copy of the real vtable of the class wrapped in @remote_class,
2271 * but all function pointers invoke the remoting functions, and
2272 * vtable->klass points to the transparent proxy class, and not to @class.
2275 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2277 MONO_REQ_GC_UNSAFE_MODE;
2280 MonoVTable *vt, *pvt;
2281 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2283 GSList *extra_interfaces = NULL;
2284 MonoClass *klass = remote_class->proxy_class;
2285 gpointer *interface_offsets;
2288 size_t imt_table_bytes;
2290 #ifdef COMPRESSED_INTERFACE_BITMAP
2294 vt = mono_class_vtable (domain, klass);
2295 g_assert (vt); /*FIXME property handle failure*/
2296 max_interface_id = vt->max_interface_id;
2298 /* Calculate vtable space for extra interfaces */
2299 for (j = 0; j < remote_class->interface_count; j++) {
2300 MonoClass* iclass = remote_class->interfaces[j];
2304 /*FIXME test for interfaces with variant generic arguments*/
2305 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, iclass->interface_id))
2306 continue; /* interface implemented by the class */
2307 if (g_slist_find (extra_interfaces, iclass))
2310 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2312 method_count = mono_class_num_methods (iclass);
2314 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2315 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2317 for (i = 0; i < ifaces->len; ++i) {
2318 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2319 /*FIXME test for interfaces with variant generic arguments*/
2320 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, ic->interface_id))
2321 continue; /* interface implemented by the class */
2322 if (g_slist_find (extra_interfaces, ic))
2324 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2325 method_count += mono_class_num_methods (ic);
2327 g_ptr_array_free (ifaces, TRUE);
2330 extra_interface_vtsize += method_count * sizeof (gpointer);
2331 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2334 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2335 mono_stats.imt_number_of_tables++;
2336 mono_stats.imt_tables_size += imt_table_bytes;
2338 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer);
2340 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2342 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2343 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2344 g_assert (!((gsize)pvt & 7));
2346 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer));
2348 pvt->klass = mono_defaults.transparent_proxy_class;
2349 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2350 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2352 /* initialize vtable */
2353 mono_class_setup_vtable (klass);
2354 for (i = 0; i < klass->vtable_size; ++i) {
2357 if ((cm = klass->vtable [i]))
2358 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2360 pvt->vtable [i] = NULL;
2363 if (klass->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2364 /* create trampolines for abstract methods */
2365 for (k = klass; k; k = k->parent) {
2367 gpointer iter = NULL;
2368 while ((m = mono_class_get_methods (k, &iter)))
2369 if (!pvt->vtable [m->slot])
2370 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2374 pvt->max_interface_id = max_interface_id;
2375 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2376 #ifdef COMPRESSED_INTERFACE_BITMAP
2377 bitmap = (uint8_t *)g_malloc0 (bsize);
2379 bitmap = (uint8_t *)mono_domain_alloc0 (domain, bsize);
2382 for (i = 0; i < klass->interface_offsets_count; ++i) {
2383 int interface_id = klass->interfaces_packed [i]->interface_id;
2384 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2387 if (extra_interfaces) {
2388 int slot = klass->vtable_size;
2394 /* Create trampolines for the methods of the interfaces */
2395 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2396 interf = (MonoClass *)list_item->data;
2398 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2402 while ((cm = mono_class_get_methods (interf, &iter)))
2403 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2405 slot += mono_class_num_methods (interf);
2409 /* Now that the vtable is full, we can actually fill up the IMT */
2410 build_imt (klass, pvt, domain, interface_offsets, extra_interfaces);
2411 if (extra_interfaces) {
2412 g_slist_free (extra_interfaces);
2415 #ifdef COMPRESSED_INTERFACE_BITMAP
2416 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2417 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2418 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2421 pvt->interface_bitmap = bitmap;
2426 #endif /* DISABLE_REMOTING */
2429 * mono_class_field_is_special_static:
2431 * Returns whether @field is a thread/context static field.
2434 mono_class_field_is_special_static (MonoClassField *field)
2436 MONO_REQ_GC_NEUTRAL_MODE
2438 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2440 if (mono_field_is_deleted (field))
2442 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2443 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2450 * mono_class_field_get_special_static_type:
2451 * @field: The MonoClassField describing the field.
2453 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2454 * SPECIAL_STATIC_NONE otherwise.
2457 mono_class_field_get_special_static_type (MonoClassField *field)
2459 MONO_REQ_GC_NEUTRAL_MODE
2461 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2462 return SPECIAL_STATIC_NONE;
2463 if (mono_field_is_deleted (field))
2464 return SPECIAL_STATIC_NONE;
2465 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2466 return field_is_special_static (field->parent, field);
2467 return SPECIAL_STATIC_NONE;
2471 * mono_class_has_special_static_fields:
2473 * Returns whenever @klass has any thread/context static fields.
2476 mono_class_has_special_static_fields (MonoClass *klass)
2478 MONO_REQ_GC_NEUTRAL_MODE
2480 MonoClassField *field;
2484 while ((field = mono_class_get_fields (klass, &iter))) {
2485 g_assert (field->parent == klass);
2486 if (mono_class_field_is_special_static (field))
2493 #ifndef DISABLE_REMOTING
2495 * create_remote_class_key:
2496 * Creates an array of pointers that can be used as a hash key for a remote class.
2497 * The first element of the array is the number of pointers.
2500 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2502 MONO_REQ_GC_NEUTRAL_MODE;
2507 if (remote_class == NULL) {
2508 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2509 key = (void **)g_malloc (sizeof(gpointer) * 3);
2510 key [0] = GINT_TO_POINTER (2);
2511 key [1] = mono_defaults.marshalbyrefobject_class;
2512 key [2] = extra_class;
2514 key = (void **)g_malloc (sizeof(gpointer) * 2);
2515 key [0] = GINT_TO_POINTER (1);
2516 key [1] = extra_class;
2519 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2520 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2521 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2522 key [1] = remote_class->proxy_class;
2524 // Keep the list of interfaces sorted
2525 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2526 if (extra_class && remote_class->interfaces [i] > extra_class) {
2527 key [j++] = extra_class;
2530 key [j] = remote_class->interfaces [i];
2533 key [j] = extra_class;
2535 // Replace the old class. The interface list is the same
2536 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2537 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2538 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2539 for (i = 0; i < remote_class->interface_count; i++)
2540 key [2 + i] = remote_class->interfaces [i];
2548 * copy_remote_class_key:
2550 * Make a copy of KEY in the domain and return the copy.
2553 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2555 MONO_REQ_GC_NEUTRAL_MODE
2557 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2558 gpointer *mp_key = (gpointer *)mono_domain_alloc (domain, key_size);
2560 memcpy (mp_key, key, key_size);
2566 * mono_remote_class:
2567 * @domain: the application domain
2568 * @class_name: name of the remote class
2570 * Creates and initializes a MonoRemoteClass object for a remote type.
2572 * Can raise an exception on failure.
2575 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2577 MONO_REQ_GC_UNSAFE_MODE;
2580 MonoRemoteClass *rc;
2581 gpointer* key, *mp_key;
2584 key = create_remote_class_key (NULL, proxy_class);
2586 mono_domain_lock (domain);
2587 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2591 mono_domain_unlock (domain);
2595 name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
2596 if (!mono_error_ok (&error)) {
2598 mono_domain_unlock (domain);
2599 mono_error_raise_exception (&error);
2602 mp_key = copy_remote_class_key (domain, key);
2606 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2607 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2608 rc->interface_count = 1;
2609 rc->interfaces [0] = proxy_class;
2610 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2612 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2613 rc->interface_count = 0;
2614 rc->proxy_class = proxy_class;
2617 rc->default_vtable = NULL;
2618 rc->xdomain_vtable = NULL;
2619 rc->proxy_class_name = name;
2620 #ifndef DISABLE_PERFCOUNTERS
2621 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2624 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2626 mono_domain_unlock (domain);
2631 * clone_remote_class:
2632 * Creates a copy of the remote_class, adding the provided class or interface
2634 static MonoRemoteClass*
2635 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2637 MONO_REQ_GC_NEUTRAL_MODE;
2639 MonoRemoteClass *rc;
2640 gpointer* key, *mp_key;
2642 key = create_remote_class_key (remote_class, extra_class);
2643 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2649 mp_key = copy_remote_class_key (domain, key);
2653 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2655 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2656 rc->proxy_class = remote_class->proxy_class;
2657 rc->interface_count = remote_class->interface_count + 1;
2659 // Keep the list of interfaces sorted, since the hash key of
2660 // the remote class depends on this
2661 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2662 if (remote_class->interfaces [i] > extra_class && i == j)
2663 rc->interfaces [j++] = extra_class;
2664 rc->interfaces [j] = remote_class->interfaces [i];
2667 rc->interfaces [j] = extra_class;
2669 // Replace the old class. The interface array is the same
2670 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2671 rc->proxy_class = extra_class;
2672 rc->interface_count = remote_class->interface_count;
2673 if (rc->interface_count > 0)
2674 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2677 rc->default_vtable = NULL;
2678 rc->xdomain_vtable = NULL;
2679 rc->proxy_class_name = remote_class->proxy_class_name;
2681 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2687 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2689 MONO_REQ_GC_UNSAFE_MODE;
2691 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2692 mono_domain_lock (domain);
2693 if (rp->target_domain_id != -1) {
2694 if (remote_class->xdomain_vtable == NULL)
2695 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2696 mono_domain_unlock (domain);
2697 mono_loader_unlock ();
2698 return remote_class->xdomain_vtable;
2700 if (remote_class->default_vtable == NULL) {
2703 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2704 klass = mono_class_from_mono_type (type);
2706 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)))
2707 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2710 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2713 mono_domain_unlock (domain);
2714 mono_loader_unlock ();
2715 return remote_class->default_vtable;
2719 * mono_upgrade_remote_class:
2720 * @domain: the application domain
2721 * @tproxy: the proxy whose remote class has to be upgraded.
2722 * @klass: class to which the remote class can be casted.
2724 * Updates the vtable of the remote class by adding the necessary method slots
2725 * and interface offsets so it can be safely casted to klass. klass can be a
2726 * class or an interface.
2729 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2731 MONO_REQ_GC_UNSAFE_MODE;
2733 MonoTransparentProxy *tproxy;
2734 MonoRemoteClass *remote_class;
2735 gboolean redo_vtable;
2737 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2738 mono_domain_lock (domain);
2740 tproxy = (MonoTransparentProxy*) proxy_object;
2741 remote_class = tproxy->remote_class;
2743 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2746 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2747 if (remote_class->interfaces [i] == klass)
2748 redo_vtable = FALSE;
2751 redo_vtable = (remote_class->proxy_class != klass);
2755 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2756 proxy_object->vtable = (MonoVTable *)mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2759 mono_domain_unlock (domain);
2760 mono_loader_unlock ();
2762 #endif /* DISABLE_REMOTING */
2766 * mono_object_get_virtual_method:
2767 * @obj: object to operate on.
2770 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2771 * the instance of a callvirt of method.
2774 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2776 MONO_REQ_GC_UNSAFE_MODE;
2779 MonoMethod **vtable;
2780 gboolean is_proxy = FALSE;
2781 MonoMethod *res = NULL;
2783 klass = mono_object_class (obj);
2784 #ifndef DISABLE_REMOTING
2785 if (klass == mono_defaults.transparent_proxy_class) {
2786 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2791 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2794 mono_class_setup_vtable (klass);
2795 vtable = klass->vtable;
2797 if (method->slot == -1) {
2798 /* method->slot might not be set for instances of generic methods */
2799 if (method->is_inflated) {
2800 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2801 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2804 g_assert_not_reached ();
2808 /* check method->slot is a valid index: perform isinstance? */
2809 if (method->slot != -1) {
2810 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2812 gboolean variance_used = FALSE;
2813 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2814 g_assert (iface_offset > 0);
2815 res = vtable [iface_offset + method->slot];
2818 res = vtable [method->slot];
2822 #ifndef DISABLE_REMOTING
2824 /* It may be an interface, abstract class method or generic method */
2825 if (!res || mono_method_signature (res)->generic_param_count)
2828 /* generic methods demand invoke_with_check */
2829 if (mono_method_signature (res)->generic_param_count)
2830 res = mono_marshal_get_remoting_invoke_with_check (res);
2833 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2834 res = mono_cominterop_get_invoke (res);
2837 res = mono_marshal_get_remoting_invoke (res);
2842 if (method->is_inflated) {
2844 /* Have to inflate the result */
2845 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, &error);
2846 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
2856 do_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2858 MONO_REQ_GC_UNSAFE_MODE;
2860 MonoObject *result = NULL;
2862 g_assert (callbacks.runtime_invoke);
2864 mono_error_init (error);
2866 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2867 mono_profiler_method_start_invoke (method);
2869 MONO_PREPARE_RESET_BLOCKING;
2871 result = callbacks.runtime_invoke (method, obj, params, exc, error);
2873 MONO_FINISH_RESET_BLOCKING;
2875 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2876 mono_profiler_method_end_invoke (method);
2878 if (!mono_error_ok (error))
2885 * mono_runtime_invoke:
2886 * @method: method to invoke
2887 * @obJ: object instance
2888 * @params: arguments to the method
2889 * @exc: exception information.
2891 * Invokes the method represented by @method on the object @obj.
2893 * obj is the 'this' pointer, it should be NULL for static
2894 * methods, a MonoObject* for object instances and a pointer to
2895 * the value type for value types.
2897 * The params array contains the arguments to the method with the
2898 * same convention: MonoObject* pointers for object instances and
2899 * pointers to the value type otherwise.
2901 * From unmanaged code you'll usually use the
2902 * mono_runtime_invoke() variant.
2904 * Note that this function doesn't handle virtual methods for
2905 * you, it will exec the exact method you pass: we still need to
2906 * expose a function to lookup the derived class implementation
2907 * of a virtual method (there are examples of this in the code,
2910 * You can pass NULL as the exc argument if you don't want to
2911 * catch exceptions, otherwise, *exc will be set to the exception
2912 * thrown, if any. if an exception is thrown, you can't use the
2913 * MonoObject* result from the function.
2915 * If the method returns a value type, it is boxed in an object
2919 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2924 res = mono_runtime_try_invoke (method, obj, params, exc, &error);
2925 if (*exc == NULL && !mono_error_ok(&error)) {
2926 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
2928 mono_error_cleanup (&error);
2930 res = mono_runtime_invoke_checked (method, obj, params, &error);
2931 mono_error_raise_exception (&error);
2937 * mono_runtime_try_invoke:
2938 * @method: method to invoke
2939 * @obJ: object instance
2940 * @params: arguments to the method
2941 * @exc: exception information.
2942 * @error: set on error
2944 * Invokes the method represented by @method on the object @obj.
2946 * obj is the 'this' pointer, it should be NULL for static
2947 * methods, a MonoObject* for object instances and a pointer to
2948 * the value type for value types.
2950 * The params array contains the arguments to the method with the
2951 * same convention: MonoObject* pointers for object instances and
2952 * pointers to the value type otherwise.
2954 * From unmanaged code you'll usually use the
2955 * mono_runtime_invoke() variant.
2957 * Note that this function doesn't handle virtual methods for
2958 * you, it will exec the exact method you pass: we still need to
2959 * expose a function to lookup the derived class implementation
2960 * of a virtual method (there are examples of this in the code,
2963 * For this function, you must not pass NULL as the exc argument if
2964 * you don't want to catch exceptions, use
2965 * mono_runtime_invoke_checked(). If an exception is thrown, you
2966 * can't use the MonoObject* result from the function.
2968 * If this method cannot be invoked, @error will be set and @exc and
2969 * the return value must not be used.
2971 * If the method returns a value type, it is boxed in an object
2975 mono_runtime_try_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError* error)
2977 MONO_REQ_GC_UNSAFE_MODE;
2979 g_assert (exc != NULL);
2981 if (mono_runtime_get_no_exec ())
2982 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2984 return do_runtime_invoke (method, obj, params, exc, error);
2988 * mono_runtime_invoke_checked:
2989 * @method: method to invoke
2990 * @obJ: object instance
2991 * @params: arguments to the method
2992 * @error: set on error
2994 * Invokes the method represented by @method on the object @obj.
2996 * obj is the 'this' pointer, it should be NULL for static
2997 * methods, a MonoObject* for object instances and a pointer to
2998 * the value type for value types.
3000 * The params array contains the arguments to the method with the
3001 * same convention: MonoObject* pointers for object instances and
3002 * pointers to the value type otherwise.
3004 * From unmanaged code you'll usually use the
3005 * mono_runtime_invoke() variant.
3007 * Note that this function doesn't handle virtual methods for
3008 * you, it will exec the exact method you pass: we still need to
3009 * expose a function to lookup the derived class implementation
3010 * of a virtual method (there are examples of this in the code,
3013 * If an exception is thrown, you can't use the MonoObject* result
3014 * from the function.
3016 * If this method cannot be invoked, @error will be set. If the
3017 * method throws an exception (and we're in coop mode) the exception
3018 * will be set in @error.
3020 * If the method returns a value type, it is boxed in an object
3024 mono_runtime_invoke_checked (MonoMethod *method, void *obj, void **params, MonoError* error)
3026 MONO_REQ_GC_UNSAFE_MODE;
3028 if (mono_runtime_get_no_exec ())
3029 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
3031 return do_runtime_invoke (method, obj, params, NULL, error);
3035 * mono_method_get_unmanaged_thunk:
3036 * @method: method to generate a thunk for.
3038 * Returns an unmanaged->managed thunk that can be used to call
3039 * a managed method directly from C.
3041 * The thunk's C signature closely matches the managed signature:
3043 * C#: public bool Equals (object obj);
3044 * C: typedef MonoBoolean (*Equals)(MonoObject*,
3045 * MonoObject*, MonoException**);
3047 * The 1st ("this") parameter must not be used with static methods:
3049 * C#: public static bool ReferenceEquals (object a, object b);
3050 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
3053 * The last argument must be a non-null pointer of a MonoException* pointer.
3054 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
3055 * exception has been thrown in managed code. Otherwise it will point
3056 * to the MonoException* caught by the thunk. In this case, the result of
3057 * the thunk is undefined:
3059 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
3060 * MonoException *ex = NULL;
3061 * Equals func = mono_method_get_unmanaged_thunk (method);
3062 * MonoBoolean res = func (thisObj, objToCompare, &ex);
3064 * // handle exception
3067 * The calling convention of the thunk matches the platform's default
3068 * convention. This means that under Windows, C declarations must
3069 * contain the __stdcall attribute:
3071 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
3072 * MonoObject*, MonoException**);
3076 * Value type arguments and return values are treated as they were objects:
3078 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
3079 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
3081 * Arguments must be properly boxed upon trunk's invocation, while return
3082 * values must be unboxed.
3085 mono_method_get_unmanaged_thunk (MonoMethod *method)
3087 MONO_REQ_GC_NEUTRAL_MODE;
3088 MONO_REQ_API_ENTRYPOINT;
3092 MONO_PREPARE_RESET_BLOCKING;
3093 method = mono_marshal_get_thunk_invoke_wrapper (method);
3094 res = mono_compile_method (method);
3095 MONO_FINISH_RESET_BLOCKING;
3101 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
3103 MONO_REQ_GC_UNSAFE_MODE;
3107 /* object fields cannot be byref, so we don't need a
3109 gpointer *p = (gpointer*)dest;
3116 case MONO_TYPE_BOOLEAN:
3118 case MONO_TYPE_U1: {
3119 guint8 *p = (guint8*)dest;
3120 *p = value ? *(guint8*)value : 0;
3125 case MONO_TYPE_CHAR: {
3126 guint16 *p = (guint16*)dest;
3127 *p = value ? *(guint16*)value : 0;
3130 #if SIZEOF_VOID_P == 4
3135 case MONO_TYPE_U4: {
3136 gint32 *p = (gint32*)dest;
3137 *p = value ? *(gint32*)value : 0;
3140 #if SIZEOF_VOID_P == 8
3145 case MONO_TYPE_U8: {
3146 gint64 *p = (gint64*)dest;
3147 *p = value ? *(gint64*)value : 0;
3150 case MONO_TYPE_R4: {
3151 float *p = (float*)dest;
3152 *p = value ? *(float*)value : 0;
3155 case MONO_TYPE_R8: {
3156 double *p = (double*)dest;
3157 *p = value ? *(double*)value : 0;
3160 case MONO_TYPE_STRING:
3161 case MONO_TYPE_SZARRAY:
3162 case MONO_TYPE_CLASS:
3163 case MONO_TYPE_OBJECT:
3164 case MONO_TYPE_ARRAY:
3165 mono_gc_wbarrier_generic_store (dest, deref_pointer ? *(MonoObject **)value : (MonoObject *)value);
3167 case MONO_TYPE_FNPTR:
3168 case MONO_TYPE_PTR: {
3169 gpointer *p = (gpointer*)dest;
3170 *p = deref_pointer? *(gpointer*)value: value;
3173 case MONO_TYPE_VALUETYPE:
3174 /* note that 't' and 'type->type' can be different */
3175 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3176 t = mono_class_enum_basetype (type->data.klass)->type;
3179 MonoClass *klass = mono_class_from_mono_type (type);
3180 int size = mono_class_value_size (klass, NULL);
3182 mono_gc_bzero_atomic (dest, size);
3184 mono_gc_wbarrier_value_copy (dest, value, 1, klass);
3187 case MONO_TYPE_GENERICINST:
3188 t = type->data.generic_class->container_class->byval_arg.type;
3191 g_error ("got type %x", type->type);
3196 * mono_field_set_value:
3197 * @obj: Instance object
3198 * @field: MonoClassField describing the field to set
3199 * @value: The value to be set
3201 * Sets the value of the field described by @field in the object instance @obj
3202 * to the value passed in @value. This method should only be used for instance
3203 * fields. For static fields, use mono_field_static_set_value.
3205 * The value must be on the native format of the field type.
3208 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3210 MONO_REQ_GC_UNSAFE_MODE;
3214 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3216 dest = (char*)obj + field->offset;
3217 mono_copy_value (field->type, dest, value, FALSE);
3221 * mono_field_static_set_value:
3222 * @field: MonoClassField describing the field to set
3223 * @value: The value to be set
3225 * Sets the value of the static field described by @field
3226 * to the value passed in @value.
3228 * The value must be on the native format of the field type.
3231 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3233 MONO_REQ_GC_UNSAFE_MODE;
3237 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3238 /* you cant set a constant! */
3239 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3241 if (field->offset == -1) {
3242 /* Special static */
3245 mono_domain_lock (vt->domain);
3246 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3247 mono_domain_unlock (vt->domain);
3248 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3250 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3252 mono_copy_value (field->type, dest, value, FALSE);
3256 * mono_vtable_get_static_field_data:
3258 * Internal use function: return a pointer to the memory holding the static fields
3259 * for a class or NULL if there are no static fields.
3260 * This is exported only for use by the debugger.
3263 mono_vtable_get_static_field_data (MonoVTable *vt)
3265 MONO_REQ_GC_NEUTRAL_MODE
3267 if (!vt->has_static_fields)
3269 return vt->vtable [vt->klass->vtable_size];
3273 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3275 MONO_REQ_GC_UNSAFE_MODE;
3279 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3280 if (field->offset == -1) {
3281 /* Special static */
3284 mono_domain_lock (vt->domain);
3285 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3286 mono_domain_unlock (vt->domain);
3287 src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3289 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3292 src = (guint8*)obj + field->offset;
3299 * mono_field_get_value:
3300 * @obj: Object instance
3301 * @field: MonoClassField describing the field to fetch information from
3302 * @value: pointer to the location where the value will be stored
3304 * Use this routine to get the value of the field @field in the object
3307 * The pointer provided by value must be of the field type, for reference
3308 * types this is a MonoObject*, for value types its the actual pointer to
3313 * mono_field_get_value (obj, int_field, &i);
3316 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3318 MONO_REQ_GC_UNSAFE_MODE;
3324 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3326 src = (char*)obj + field->offset;
3327 mono_copy_value (field->type, value, src, TRUE);
3331 * mono_field_get_value_object:
3332 * @domain: domain where the object will be created (if boxing)
3333 * @field: MonoClassField describing the field to fetch information from
3334 * @obj: The object instance for the field.
3336 * Returns: a new MonoObject with the value from the given field. If the
3337 * field represents a value type, the value is boxed.
3341 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3343 MONO_REQ_GC_UNSAFE_MODE;
3348 MonoVTable *vtable = NULL;
3350 gboolean is_static = FALSE;
3351 gboolean is_ref = FALSE;
3352 gboolean is_literal = FALSE;
3353 gboolean is_ptr = FALSE;
3354 MonoType *type = mono_field_get_type_checked (field, &error);
3356 if (!mono_error_ok (&error))
3357 mono_error_raise_exception (&error);
3359 switch (type->type) {
3360 case MONO_TYPE_STRING:
3361 case MONO_TYPE_OBJECT:
3362 case MONO_TYPE_CLASS:
3363 case MONO_TYPE_ARRAY:
3364 case MONO_TYPE_SZARRAY:
3369 case MONO_TYPE_BOOLEAN:
3372 case MONO_TYPE_CHAR:
3381 case MONO_TYPE_VALUETYPE:
3382 is_ref = type->byref;
3384 case MONO_TYPE_GENERICINST:
3385 is_ref = !mono_type_generic_inst_is_valuetype (type);
3391 g_error ("type 0x%x not handled in "
3392 "mono_field_get_value_object", type->type);
3396 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3399 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3403 vtable = mono_class_vtable_full (domain, field->parent, TRUE);
3404 if (!vtable->initialized)
3405 mono_runtime_class_init (vtable);
3413 get_default_field_value (domain, field, &o);
3414 } else if (is_static) {
3415 mono_field_static_get_value (vtable, field, &o);
3417 mono_field_get_value (obj, field, &o);
3423 static MonoMethod *m;
3429 MonoClass *ptr_klass = mono_class_get_pointer_class ();
3430 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3436 get_default_field_value (domain, field, v);
3437 } else if (is_static) {
3438 mono_field_static_get_value (vtable, field, v);
3440 mono_field_get_value (obj, field, v);
3443 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3444 args [0] = ptr ? *ptr : NULL;
3445 args [1] = mono_type_get_object_checked (mono_domain_get (), type, &error);
3446 mono_error_raise_exception (&error); /* FIXME don't raise here */
3448 o = mono_runtime_invoke_checked (m, NULL, args, &error);
3449 mono_error_raise_exception (&error); /* FIXME don't raise here */
3454 /* boxed value type */
3455 klass = mono_class_from_mono_type (type);
3457 if (mono_class_is_nullable (klass))
3458 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
3460 o = mono_object_new_checked (domain, klass, &error);
3461 mono_error_raise_exception (&error); /* FIXME don't raise here */
3462 v = ((gchar *) o) + sizeof (MonoObject);
3465 get_default_field_value (domain, field, v);
3466 } else if (is_static) {
3467 mono_field_static_get_value (vtable, field, v);
3469 mono_field_get_value (obj, field, v);
3476 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
3478 MONO_REQ_GC_UNSAFE_MODE;
3481 const char *p = blob;
3482 mono_metadata_decode_blob_size (p, &p);
3485 case MONO_TYPE_BOOLEAN:
3488 *(guint8 *) value = *p;
3490 case MONO_TYPE_CHAR:
3493 *(guint16*) value = read16 (p);
3497 *(guint32*) value = read32 (p);
3501 *(guint64*) value = read64 (p);
3504 readr4 (p, (float*) value);
3507 readr8 (p, (double*) value);
3509 case MONO_TYPE_STRING:
3510 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3512 case MONO_TYPE_CLASS:
3513 *(gpointer*) value = NULL;
3517 g_warning ("type 0x%02x should not be in constant table", type);
3523 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3525 MONO_REQ_GC_NEUTRAL_MODE;
3527 MonoTypeEnum def_type;
3530 data = mono_class_get_field_default_value (field, &def_type);
3531 mono_get_constant_value_from_blob (domain, def_type, data, value);
3535 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value)
3537 MONO_REQ_GC_UNSAFE_MODE;
3541 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3543 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3544 get_default_field_value (vt->domain, field, value);
3548 if (field->offset == -1) {
3549 /* Special static */
3550 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3551 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3553 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3555 mono_copy_value (field->type, value, src, TRUE);
3559 * mono_field_static_get_value:
3560 * @vt: vtable to the object
3561 * @field: MonoClassField describing the field to fetch information from
3562 * @value: where the value is returned
3564 * Use this routine to get the value of the static field @field value.
3566 * The pointer provided by value must be of the field type, for reference
3567 * types this is a MonoObject*, for value types its the actual pointer to
3572 * mono_field_static_get_value (vt, int_field, &i);
3575 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3577 MONO_REQ_GC_NEUTRAL_MODE;
3579 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value);
3583 * mono_property_set_value:
3584 * @prop: MonoProperty to set
3585 * @obj: instance object on which to act
3586 * @params: parameters to pass to the propery
3587 * @exc: optional exception
3589 * Invokes the property's set method with the given arguments on the
3590 * object instance obj (or NULL for static properties).
3592 * You can pass NULL as the exc argument if you don't want to
3593 * catch exceptions, otherwise, *exc will be set to the exception
3594 * thrown, if any. if an exception is thrown, you can't use the
3595 * MonoObject* result from the function.
3598 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3600 MONO_REQ_GC_UNSAFE_MODE;
3603 do_runtime_invoke (prop->set, obj, params, exc, &error);
3604 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3605 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3607 mono_error_raise_exception (&error); /* FIXME don't raise here */
3612 * mono_property_get_value:
3613 * @prop: MonoProperty to fetch
3614 * @obj: instance object on which to act
3615 * @params: parameters to pass to the propery
3616 * @exc: optional exception
3618 * Invokes the property's get method with the given arguments on the
3619 * object instance obj (or NULL for static properties).
3621 * You can pass NULL as the exc argument if you don't want to
3622 * catch exceptions, otherwise, *exc will be set to the exception
3623 * thrown, if any. if an exception is thrown, you can't use the
3624 * MonoObject* result from the function.
3626 * Returns: the value from invoking the get method on the property.
3629 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3631 MONO_REQ_GC_UNSAFE_MODE;
3634 MonoObject *val = do_runtime_invoke (prop->get, obj, params, exc, &error);
3635 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3636 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3638 mono_error_raise_exception (&error); /* FIXME don't raise here */
3645 * mono_nullable_init:
3646 * @buf: The nullable structure to initialize.
3647 * @value: the value to initialize from
3648 * @klass: the type for the object
3650 * Initialize the nullable structure pointed to by @buf from @value which
3651 * should be a boxed value type. The size of @buf should be able to hold
3652 * as much data as the @klass->instance_size (which is the number of bytes
3653 * that will be copies).
3655 * Since Nullables have variable structure, we can not define a C
3656 * structure for them.
3659 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3661 MONO_REQ_GC_UNSAFE_MODE;
3663 MonoClass *param_class = klass->cast_class;
3665 mono_class_setup_fields_locking (klass);
3666 g_assert (klass->fields_inited);
3668 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3669 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3671 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3673 if (param_class->has_references)
3674 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3676 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3678 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3683 * mono_nullable_box:
3684 * @buf: The buffer representing the data to be boxed
3685 * @klass: the type to box it as.
3687 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3691 mono_nullable_box (guint8 *buf, MonoClass *klass)
3693 MONO_REQ_GC_UNSAFE_MODE;
3697 MonoClass *param_class = klass->cast_class;
3699 mono_class_setup_fields_locking (klass);
3700 g_assert (klass->fields_inited);
3702 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3703 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3705 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3706 MonoObject *o = mono_object_new_checked (mono_domain_get (), param_class, &error);
3707 mono_error_raise_exception (&error); /* FIXME don't raise here */
3708 if (param_class->has_references)
3709 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3711 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3719 * mono_get_delegate_invoke:
3720 * @klass: The delegate class
3722 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3725 mono_get_delegate_invoke (MonoClass *klass)
3727 MONO_REQ_GC_NEUTRAL_MODE;
3731 /* This is called at runtime, so avoid the slower search in metadata */
3732 mono_class_setup_methods (klass);
3733 if (klass->exception_type)
3735 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3740 * mono_get_delegate_begin_invoke:
3741 * @klass: The delegate class
3743 * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3746 mono_get_delegate_begin_invoke (MonoClass *klass)
3748 MONO_REQ_GC_NEUTRAL_MODE;
3752 /* This is called at runtime, so avoid the slower search in metadata */
3753 mono_class_setup_methods (klass);
3754 if (klass->exception_type)
3756 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3761 * mono_get_delegate_end_invoke:
3762 * @klass: The delegate class
3764 * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3767 mono_get_delegate_end_invoke (MonoClass *klass)
3769 MONO_REQ_GC_NEUTRAL_MODE;
3773 /* This is called at runtime, so avoid the slower search in metadata */
3774 mono_class_setup_methods (klass);
3775 if (klass->exception_type)
3777 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3782 * mono_runtime_delegate_invoke:
3783 * @delegate: pointer to a delegate object.
3784 * @params: parameters for the delegate.
3785 * @exc: Pointer to the exception result.
3787 * Invokes the delegate method @delegate with the parameters provided.
3789 * You can pass NULL as the exc argument if you don't want to
3790 * catch exceptions, otherwise, *exc will be set to the exception
3791 * thrown, if any. if an exception is thrown, you can't use the
3792 * MonoObject* result from the function.
3795 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3797 MONO_REQ_GC_UNSAFE_MODE;
3801 MonoClass *klass = delegate->vtable->klass;
3804 im = mono_get_delegate_invoke (klass);
3806 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3809 o = mono_runtime_try_invoke (im, delegate, params, exc, &error);
3810 if (*exc == NULL && !mono_error_ok (&error))
3811 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3813 mono_error_cleanup (&error);
3815 o = mono_runtime_invoke_checked (im, delegate, params, &error);
3816 mono_error_raise_exception (&error); /* FIXME don't raise here */
3822 static char **main_args = NULL;
3823 static int num_main_args = 0;
3826 * mono_runtime_get_main_args:
3828 * Returns: a MonoArray with the arguments passed to the main program
3831 mono_runtime_get_main_args (void)
3833 MONO_REQ_GC_UNSAFE_MODE;
3837 MonoDomain *domain = mono_domain_get ();
3839 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3841 for (i = 0; i < num_main_args; ++i)
3842 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3848 free_main_args (void)
3850 MONO_REQ_GC_NEUTRAL_MODE;
3854 for (i = 0; i < num_main_args; ++i)
3855 g_free (main_args [i]);
3862 * mono_runtime_set_main_args:
3863 * @argc: number of arguments from the command line
3864 * @argv: array of strings from the command line
3866 * Set the command line arguments from an embedding application that doesn't otherwise call
3867 * mono_runtime_run_main ().
3870 mono_runtime_set_main_args (int argc, char* argv[])
3872 MONO_REQ_GC_NEUTRAL_MODE;
3877 main_args = g_new0 (char*, argc);
3878 num_main_args = argc;
3880 for (i = 0; i < argc; ++i) {
3883 utf8_arg = mono_utf8_from_external (argv[i]);
3884 if (utf8_arg == NULL) {
3885 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
3886 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3890 main_args [i] = utf8_arg;
3897 * mono_runtime_run_main:
3898 * @method: the method to start the application with (usually Main)
3899 * @argc: number of arguments from the command line
3900 * @argv: array of strings from the command line
3901 * @exc: excetption results
3903 * Execute a standard Main() method (argc/argv contains the
3904 * executable name). This method also sets the command line argument value
3905 * needed by System.Environment.
3910 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3913 MONO_REQ_GC_UNSAFE_MODE;
3916 MonoArray *args = NULL;
3917 MonoDomain *domain = mono_domain_get ();
3918 gchar *utf8_fullpath;
3919 MonoMethodSignature *sig;
3921 g_assert (method != NULL);
3923 mono_thread_set_main (mono_thread_current ());
3925 main_args = g_new0 (char*, argc);
3926 num_main_args = argc;
3928 if (!g_path_is_absolute (argv [0])) {
3929 gchar *basename = g_path_get_basename (argv [0]);
3930 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3934 utf8_fullpath = mono_utf8_from_external (fullpath);
3935 if(utf8_fullpath == NULL) {
3936 /* Printing the arg text will cause glib to
3937 * whinge about "Invalid UTF-8", but at least
3938 * its relevant, and shows the problem text
3941 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3942 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3949 utf8_fullpath = mono_utf8_from_external (argv[0]);
3950 if(utf8_fullpath == NULL) {
3951 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3952 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3957 main_args [0] = utf8_fullpath;
3959 for (i = 1; i < argc; ++i) {
3962 utf8_arg=mono_utf8_from_external (argv[i]);
3963 if(utf8_arg==NULL) {
3964 /* Ditto the comment about Invalid UTF-8 here */
3965 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3966 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3970 main_args [i] = utf8_arg;
3975 sig = mono_method_signature (method);
3977 g_print ("Unable to load Main method.\n");
3981 if (sig->param_count) {
3982 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3983 for (i = 0; i < argc; ++i) {
3984 /* The encodings should all work, given that
3985 * we've checked all these args for the
3988 gchar *str = mono_utf8_from_external (argv [i]);
3989 MonoString *arg = mono_string_new (domain, str);
3990 mono_array_setref (args, i, arg);
3994 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3997 mono_assembly_set_main (method->klass->image->assembly);
3999 return mono_runtime_exec_main (method, args, exc);
4003 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4005 static MonoMethod *serialize_method;
4011 if (!serialize_method) {
4012 MonoClass *klass = mono_class_get_remoting_services_class ();
4013 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
4016 if (!serialize_method) {
4021 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
4026 array = mono_runtime_try_invoke (serialize_method, NULL, params, exc, &error);
4027 if (*exc == NULL && !mono_error_ok (&error))
4028 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert serialize_object to MonoError */
4030 mono_error_cleanup (&error);
4039 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4041 MONO_REQ_GC_UNSAFE_MODE;
4043 static MonoMethod *deserialize_method;
4049 if (!deserialize_method) {
4050 MonoClass *klass = mono_class_get_remoting_services_class ();
4051 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
4053 if (!deserialize_method) {
4061 result = mono_runtime_try_invoke (deserialize_method, NULL, params, exc, &error);
4062 if (*exc == NULL && !mono_error_ok (&error))
4063 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert deserialize_object to MonoError */
4065 mono_error_cleanup (&error);
4073 #ifndef DISABLE_REMOTING
4075 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
4077 MONO_REQ_GC_UNSAFE_MODE;
4079 static MonoMethod *get_proxy_method;
4082 MonoDomain *domain = mono_domain_get ();
4083 MonoRealProxy *real_proxy;
4084 MonoReflectionType *reflection_type;
4085 MonoTransparentProxy *transparent_proxy;
4087 if (!get_proxy_method)
4088 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
4090 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
4092 real_proxy = (MonoRealProxy*) mono_object_new_checked (domain, mono_defaults.real_proxy_class, &error);
4093 mono_error_raise_exception (&error); /* FIXME don't raise here */
4094 reflection_type = mono_type_get_object_checked (domain, &obj->vtable->klass->byval_arg, &error);
4095 mono_error_raise_exception (&error); /* FIXME don't raise here */
4097 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
4098 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
4102 transparent_proxy = (MonoTransparentProxy*) mono_runtime_try_invoke (get_proxy_method, real_proxy, NULL, exc, &error);
4103 if (*exc == NULL && !mono_error_ok (&error))
4104 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME change make_transparent_proxy outarg to MonoError */
4106 mono_error_cleanup (&error);
4110 return (MonoObject*) transparent_proxy;
4112 #endif /* DISABLE_REMOTING */
4115 * mono_object_xdomain_representation
4117 * @target_domain: a domain
4118 * @exc: pointer to a MonoObject*
4120 * Creates a representation of obj in the domain target_domain. This
4121 * is either a copy of obj arrived through via serialization and
4122 * deserialization or a proxy, depending on whether the object is
4123 * serializable or marshal by ref. obj must not be in target_domain.
4125 * If the object cannot be represented in target_domain, NULL is
4126 * returned and *exc is set to an appropriate exception.
4129 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
4131 MONO_REQ_GC_UNSAFE_MODE;
4133 MonoObject *deserialized = NULL;
4134 gboolean failure = FALSE;
4136 g_assert (exc != NULL);
4139 #ifndef DISABLE_REMOTING
4140 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
4141 deserialized = make_transparent_proxy (obj, &failure, exc);
4146 MonoDomain *domain = mono_domain_get ();
4147 MonoObject *serialized;
4149 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
4150 serialized = serialize_object (obj, &failure, exc);
4151 mono_domain_set_internal_with_options (target_domain, FALSE);
4153 deserialized = deserialize_object (serialized, &failure, exc);
4154 if (domain != target_domain)
4155 mono_domain_set_internal_with_options (domain, FALSE);
4158 return deserialized;
4161 /* Used in call_unhandled_exception_delegate */
4163 create_unhandled_exception_eventargs (MonoObject *exc)
4165 MONO_REQ_GC_UNSAFE_MODE;
4170 MonoMethod *method = NULL;
4171 MonoBoolean is_terminating = TRUE;
4174 klass = mono_class_get_unhandled_exception_event_args_class ();
4175 mono_class_init (klass);
4177 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4178 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
4182 args [1] = &is_terminating;
4184 obj = mono_object_new_checked (mono_domain_get (), klass, &error);
4185 mono_error_raise_exception (&error); /* FIXME don't raise here */
4187 mono_runtime_invoke_checked (method, obj, args, &error);
4188 mono_error_raise_exception (&error); /* FIXME don't raise here */
4193 /* Used in mono_unhandled_exception */
4195 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4196 MONO_REQ_GC_UNSAFE_MODE;
4198 MonoObject *e = NULL;
4200 MonoDomain *current_domain = mono_domain_get ();
4202 if (domain != current_domain)
4203 mono_domain_set_internal_with_options (domain, FALSE);
4205 g_assert (domain == mono_object_domain (domain->domain));
4207 if (mono_object_domain (exc) != domain) {
4208 MonoObject *serialization_exc;
4210 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
4212 if (serialization_exc) {
4214 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
4217 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4218 "System.Runtime.Serialization", "SerializationException",
4219 "Could not serialize unhandled exception.");
4223 g_assert (mono_object_domain (exc) == domain);
4225 pa [0] = domain->domain;
4226 pa [1] = create_unhandled_exception_eventargs (exc);
4227 mono_runtime_delegate_invoke (delegate, pa, &e);
4229 if (domain != current_domain)
4230 mono_domain_set_internal_with_options (current_domain, FALSE);
4234 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4235 if (!mono_error_ok (&error)) {
4236 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4237 mono_error_cleanup (&error);
4239 g_warning ("exception inside UnhandledException handler: %s\n", msg);
4245 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4248 * mono_runtime_unhandled_exception_policy_set:
4249 * @policy: the new policy
4251 * This is a VM internal routine.
4253 * Sets the runtime policy for handling unhandled exceptions.
4256 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4257 runtime_unhandled_exception_policy = policy;
4261 * mono_runtime_unhandled_exception_policy_get:
4263 * This is a VM internal routine.
4265 * Gets the runtime policy for handling unhandled exceptions.
4267 MonoRuntimeUnhandledExceptionPolicy
4268 mono_runtime_unhandled_exception_policy_get (void) {
4269 return runtime_unhandled_exception_policy;
4273 * mono_unhandled_exception:
4274 * @exc: exception thrown
4276 * This is a VM internal routine.
4278 * We call this function when we detect an unhandled exception
4279 * in the default domain.
4281 * It invokes the * UnhandledException event in AppDomain or prints
4282 * a warning to the console
4285 mono_unhandled_exception (MonoObject *exc)
4287 MONO_REQ_GC_UNSAFE_MODE;
4289 MonoClassField *field;
4290 MonoDomain *current_domain, *root_domain;
4291 MonoObject *current_appdomain_delegate = NULL, *root_appdomain_delegate = NULL;
4293 if (mono_class_has_parent (exc->vtable->klass, mono_defaults.threadabortexception_class))
4296 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4299 current_domain = mono_domain_get ();
4300 root_domain = mono_get_root_domain ();
4302 root_appdomain_delegate = mono_field_get_value_object (root_domain, field, (MonoObject*) root_domain->domain);
4303 if (current_domain != root_domain)
4304 current_appdomain_delegate = mono_field_get_value_object (current_domain, field, (MonoObject*) current_domain->domain);
4306 /* set exitcode only if we will abort the process */
4307 if (!current_appdomain_delegate && !root_appdomain_delegate) {
4308 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4309 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4311 mono_environment_exitcode_set (1);
4314 mono_print_unhandled_exception (exc);
4316 if (root_appdomain_delegate)
4317 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4318 if (current_appdomain_delegate)
4319 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4324 * mono_runtime_exec_managed_code:
4325 * @domain: Application domain
4326 * @main_func: function to invoke from the execution thread
4327 * @main_args: parameter to the main_func
4329 * Launch a new thread to execute a function
4331 * main_func is called back from the thread with main_args as the
4332 * parameter. The callback function is expected to start Main()
4333 * eventually. This function then waits for all managed threads to
4335 * It is not necesseray anymore to execute managed code in a subthread,
4336 * so this function should not be used anymore by default: just
4337 * execute the code and then call mono_thread_manage ().
4340 mono_runtime_exec_managed_code (MonoDomain *domain,
4341 MonoMainThreadFunc main_func,
4344 mono_thread_create (domain, main_func, main_args);
4346 mono_thread_manage ();
4350 * Execute a standard Main() method (args doesn't contain the
4354 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4356 MONO_REQ_GC_UNSAFE_MODE;
4362 MonoCustomAttrInfo* cinfo;
4363 gboolean has_stathread_attribute;
4364 MonoInternalThread* thread = mono_thread_internal_current ();
4370 domain = mono_object_domain (args);
4371 if (!domain->entry_assembly) {
4373 MonoAssembly *assembly;
4375 assembly = method->klass->image->assembly;
4376 domain->entry_assembly = assembly;
4377 /* Domains created from another domain already have application_base and configuration_file set */
4378 if (domain->setup->application_base == NULL) {
4379 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4382 if (domain->setup->configuration_file == NULL) {
4383 str = g_strconcat (assembly->image->name, ".config", NULL);
4384 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4386 mono_domain_set_options_from_config (domain);
4390 cinfo = mono_custom_attrs_from_method (method);
4392 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, mono_class_get_sta_thread_attribute_class ());
4394 mono_custom_attrs_free (cinfo);
4396 has_stathread_attribute = FALSE;
4398 if (has_stathread_attribute) {
4399 thread->apartment_state = ThreadApartmentState_STA;
4401 thread->apartment_state = ThreadApartmentState_MTA;
4403 mono_thread_init_apartment_state ();
4405 /* FIXME: check signature of method */
4406 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4409 res = mono_runtime_try_invoke (method, NULL, pa, exc, &error);
4410 if (*exc == NULL && !mono_error_ok (&error))
4411 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4413 mono_error_cleanup (&error);
4415 res = mono_runtime_invoke_checked (method, NULL, pa, &error);
4416 mono_error_raise_exception (&error); /* FIXME don't raise here */
4420 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4424 mono_environment_exitcode_set (rval);
4427 mono_runtime_try_invoke (method, NULL, pa, exc, &error);
4428 if (*exc == NULL && !mono_error_ok (&error))
4429 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4431 mono_error_cleanup (&error);
4433 mono_runtime_invoke_checked (method, NULL, pa, &error);
4434 mono_error_raise_exception (&error); /* FIXME don't raise here */
4440 /* If the return type of Main is void, only
4441 * set the exitcode if an exception was thrown
4442 * (we don't want to blow away an
4443 * explicitly-set exit code)
4446 mono_environment_exitcode_set (rval);
4454 * mono_runtime_invoke_array:
4455 * @method: method to invoke
4456 * @obJ: object instance
4457 * @params: arguments to the method
4458 * @exc: exception information.
4460 * Invokes the method represented by @method on the object @obj.
4462 * obj is the 'this' pointer, it should be NULL for static
4463 * methods, a MonoObject* for object instances and a pointer to
4464 * the value type for value types.
4466 * The params array contains the arguments to the method with the
4467 * same convention: MonoObject* pointers for object instances and
4468 * pointers to the value type otherwise. The _invoke_array
4469 * variant takes a C# object[] as the params argument (MonoArray
4470 * *params): in this case the value types are boxed inside the
4471 * respective reference representation.
4473 * From unmanaged code you'll usually use the
4474 * mono_runtime_invoke_checked() variant.
4476 * Note that this function doesn't handle virtual methods for
4477 * you, it will exec the exact method you pass: we still need to
4478 * expose a function to lookup the derived class implementation
4479 * of a virtual method (there are examples of this in the code,
4482 * You can pass NULL as the exc argument if you don't want to
4483 * catch exceptions, otherwise, *exc will be set to the exception
4484 * thrown, if any. if an exception is thrown, you can't use the
4485 * MonoObject* result from the function.
4487 * If the method returns a value type, it is boxed in an object
4491 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4494 MONO_REQ_GC_UNSAFE_MODE;
4497 MonoMethodSignature *sig = mono_method_signature (method);
4498 gpointer *pa = NULL;
4501 gboolean has_byref_nullables = FALSE;
4503 if (NULL != params) {
4504 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
4505 for (i = 0; i < mono_array_length (params); i++) {
4506 MonoType *t = sig->params [i];
4512 case MONO_TYPE_BOOLEAN:
4515 case MONO_TYPE_CHAR:
4524 case MONO_TYPE_VALUETYPE:
4525 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
4526 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4527 pa [i] = mono_array_get (params, MonoObject*, i);
4529 has_byref_nullables = TRUE;
4531 /* MS seems to create the objects if a null is passed in */
4532 if (!mono_array_get (params, MonoObject*, i)) {
4533 MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (sig->params [i]), &error);
4534 mono_error_raise_exception (&error); /* FIXME don't raise here */
4535 mono_array_setref (params, i, o);
4540 * We can't pass the unboxed vtype byref to the callee, since
4541 * that would mean the callee would be able to modify boxed
4542 * primitive types. So we (and MS) make a copy of the boxed
4543 * object, pass that to the callee, and replace the original
4544 * boxed object in the arg array with the copy.
4546 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4547 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
4548 mono_array_setref (params, i, copy);
4551 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4554 case MONO_TYPE_STRING:
4555 case MONO_TYPE_OBJECT:
4556 case MONO_TYPE_CLASS:
4557 case MONO_TYPE_ARRAY:
4558 case MONO_TYPE_SZARRAY:
4560 pa [i] = mono_array_addr (params, MonoObject*, i);
4561 // FIXME: I need to check this code path
4563 pa [i] = mono_array_get (params, MonoObject*, i);
4565 case MONO_TYPE_GENERICINST:
4567 t = &t->data.generic_class->container_class->this_arg;
4569 t = &t->data.generic_class->container_class->byval_arg;
4571 case MONO_TYPE_PTR: {
4574 /* The argument should be an IntPtr */
4575 arg = mono_array_get (params, MonoObject*, i);
4579 g_assert (arg->vtable->klass == mono_defaults.int_class);
4580 pa [i] = ((MonoIntPtr*)arg)->m_value;
4585 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
4590 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4593 if (mono_class_is_nullable (method->klass)) {
4594 /* Need to create a boxed vtype instead */
4600 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
4604 obj = mono_object_new_checked (mono_domain_get (), method->klass, &error);
4605 g_assert (obj && mono_error_ok (&error)); /*maybe we should raise a TLE instead?*/ /* FIXME don't swallow error */
4606 #ifndef DISABLE_REMOTING
4607 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
4608 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
4611 if (method->klass->valuetype)
4612 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
4615 } else if (method->klass->valuetype) {
4616 obj = mono_value_box (mono_domain_get (), method->klass, obj);
4620 mono_runtime_try_invoke (method, o, pa, exc, &error);
4621 if (*exc == NULL && !mono_error_ok (&error))
4622 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4624 mono_error_cleanup (&error);
4626 mono_runtime_invoke_checked (method, o, pa, &error);
4627 mono_error_raise_exception (&error); /* FIXME don't raise here */
4630 return (MonoObject *)obj;
4632 if (mono_class_is_nullable (method->klass)) {
4633 MonoObject *nullable;
4635 /* Convert the unboxed vtype into a Nullable structure */
4636 nullable = mono_object_new_checked (mono_domain_get (), method->klass, &error);
4637 mono_error_raise_exception (&error); /* FIXME don't raise here */
4639 mono_nullable_init ((guint8 *)mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
4640 obj = mono_object_unbox (nullable);
4643 /* obj must be already unboxed if needed */
4645 res = mono_runtime_try_invoke (method, obj, pa, exc, &error);
4646 if (*exc == NULL && !mono_error_ok (&error))
4647 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4649 mono_error_cleanup (&error);
4651 res = mono_runtime_invoke_checked (method, obj, pa, &error);
4652 mono_error_raise_exception (&error); /* FIXME don't raise here */
4655 if (sig->ret->type == MONO_TYPE_PTR) {
4656 MonoClass *pointer_class;
4657 static MonoMethod *box_method;
4659 MonoObject *box_exc;
4662 * The runtime-invoke wrapper returns a boxed IntPtr, need to
4663 * convert it to a Pointer object.
4665 pointer_class = mono_class_get_pointer_class ();
4667 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4669 g_assert (res->vtable->klass == mono_defaults.int_class);
4670 box_args [0] = ((MonoIntPtr*)res)->m_value;
4671 box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, &error);
4672 mono_error_raise_exception (&error); /* FIXME don't raise here */
4674 res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, &error);
4675 g_assert (box_exc == NULL);
4676 mono_error_assert_ok (&error);
4679 if (has_byref_nullables) {
4681 * The runtime invoke wrapper already converted byref nullables back,
4682 * and stored them in pa, we just need to copy them back to the
4685 for (i = 0; i < mono_array_length (params); i++) {
4686 MonoType *t = sig->params [i];
4688 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4689 mono_array_setref (params, i, pa [i]);
4699 * @klass: the class of the object that we want to create
4701 * Returns: a newly created object whose definition is
4702 * looked up using @klass. This will not invoke any constructors,
4703 * so the consumer of this routine has to invoke any constructors on
4704 * its own to initialize the object.
4706 * It returns NULL on failure.
4709 mono_object_new (MonoDomain *domain, MonoClass *klass)
4711 MONO_REQ_GC_UNSAFE_MODE;
4715 MonoObject * result = mono_object_new_checked (domain, klass, &error);
4717 mono_error_raise_exception (&error);
4722 ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
4724 MONO_REQ_GC_UNSAFE_MODE;
4728 MonoObject * result = mono_object_new_checked (domain, klass, &error);
4730 mono_error_raise_exception (&error);
4735 * mono_object_new_checked:
4736 * @klass: the class of the object that we want to create
4737 * @error: set on error
4739 * Returns: a newly created object whose definition is
4740 * looked up using @klass. This will not invoke any constructors,
4741 * so the consumer of this routine has to invoke any constructors on
4742 * its own to initialize the object.
4744 * It returns NULL on failure and sets @error.
4747 mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
4749 MONO_REQ_GC_UNSAFE_MODE;
4753 vtable = mono_class_vtable (domain, klass);
4754 g_assert (vtable); /* FIXME don't swallow the error */
4756 MonoObject *o = mono_object_new_specific_checked (vtable, error);
4761 * mono_object_new_pinned:
4763 * Same as mono_object_new, but the returned object will be pinned.
4764 * For SGEN, these objects will only be freed at appdomain unload.
4767 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
4769 MONO_REQ_GC_UNSAFE_MODE;
4773 mono_error_init (error);
4775 vtable = mono_class_vtable (domain, klass);
4776 g_assert (vtable); /* FIXME don't swallow the error */
4778 MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
4780 if (G_UNLIKELY (!o))
4781 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
4782 else if (G_UNLIKELY (vtable->klass->has_finalize))
4783 mono_object_register_finalizer (o);
4789 * mono_object_new_specific:
4790 * @vtable: the vtable of the object that we want to create
4792 * Returns: A newly created object with class and domain specified
4796 mono_object_new_specific (MonoVTable *vtable)
4799 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
4800 mono_error_raise_exception (&error);
4806 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
4808 MONO_REQ_GC_UNSAFE_MODE;
4812 mono_error_init (error);
4814 /* check for is_com_object for COM Interop */
4815 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
4818 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4821 MonoClass *klass = mono_class_get_activation_services_class ();
4824 mono_class_init (klass);
4826 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4828 mono_error_set_generic_error (error, "System", "NotSupportedException", "Linked away.");
4831 vtable->domain->create_proxy_for_type_method = im;
4834 pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
4835 if (!mono_error_ok (error))
4838 o = mono_runtime_invoke_checked (im, NULL, pa, error);
4839 if (!mono_error_ok (error))
4846 return mono_object_new_alloc_specific_checked (vtable, error);
4850 ves_icall_object_new_specific (MonoVTable *vtable)
4853 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
4854 mono_error_raise_exception (&error);
4860 * mono_object_new_alloc_specific:
4861 * @vtable: virtual table for the object.
4863 * This function allocates a new `MonoObject` with the type derived
4864 * from the @vtable information. If the class of this object has a
4865 * finalizer, then the object will be tracked for finalization.
4867 * This method might raise an exception on errors. Use the
4868 * `mono_object_new_fast_checked` method if you want to manually raise
4871 * Returns: the allocated object.
4874 mono_object_new_alloc_specific (MonoVTable *vtable)
4877 MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
4878 mono_error_raise_exception (&error);
4884 * mono_object_new_alloc_specific_checked:
4885 * @vtable: virtual table for the object.
4886 * @error: holds the error return value.
4888 * This function allocates a new `MonoObject` with the type derived
4889 * from the @vtable information. If the class of this object has a
4890 * finalizer, then the object will be tracked for finalization.
4892 * If there is not enough memory, the @error parameter will be set
4893 * and will contain a user-visible message with the amount of bytes
4894 * that were requested.
4896 * Returns: the allocated object, or NULL if there is not enough memory
4900 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
4902 MONO_REQ_GC_UNSAFE_MODE;
4906 mono_error_init (error);
4908 o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
4910 if (G_UNLIKELY (!o))
4911 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
4912 else if (G_UNLIKELY (vtable->klass->has_finalize))
4913 mono_object_register_finalizer (o);
4919 * mono_object_new_fast:
4920 * @vtable: virtual table for the object.
4922 * This function allocates a new `MonoObject` with the type derived
4923 * from the @vtable information. The returned object is not tracked
4924 * for finalization. If your object implements a finalizer, you should
4925 * use `mono_object_new_alloc_specific` instead.
4927 * This method might raise an exception on errors. Use the
4928 * `mono_object_new_fast_checked` method if you want to manually raise
4931 * Returns: the allocated object.
4934 mono_object_new_fast (MonoVTable *vtable)
4937 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
4938 mono_error_raise_exception (&error);
4944 * mono_object_new_fast_checked:
4945 * @vtable: virtual table for the object.
4946 * @error: holds the error return value.
4948 * This function allocates a new `MonoObject` with the type derived
4949 * from the @vtable information. The returned object is not tracked
4950 * for finalization. If your object implements a finalizer, you should
4951 * use `mono_object_new_alloc_specific_checked` instead.
4953 * If there is not enough memory, the @error parameter will be set
4954 * and will contain a user-visible message with the amount of bytes
4955 * that were requested.
4957 * Returns: the allocated object, or NULL if there is not enough memory
4961 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
4963 MONO_REQ_GC_UNSAFE_MODE;
4967 mono_error_init (error);
4969 o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
4971 if (G_UNLIKELY (!o))
4972 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
4978 ves_icall_object_new_fast (MonoVTable *vtable)
4981 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
4982 mono_error_raise_exception (&error);
4988 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
4990 MONO_REQ_GC_UNSAFE_MODE;
4994 mono_error_init (error);
4996 o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
4998 if (G_UNLIKELY (!o))
4999 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5000 else if (G_UNLIKELY (vtable->klass->has_finalize))
5001 mono_object_register_finalizer (o);
5007 * mono_class_get_allocation_ftn:
5009 * @for_box: the object will be used for boxing
5010 * @pass_size_in_words:
5012 * Return the allocation function appropriate for the given class.
5016 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
5018 MONO_REQ_GC_NEUTRAL_MODE;
5020 *pass_size_in_words = FALSE;
5022 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass) || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
5023 return ves_icall_object_new_specific;
5025 if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
5027 return ves_icall_object_new_fast;
5030 * FIXME: This is actually slower than ves_icall_object_new_fast, because
5031 * of the overhead of parameter passing.
5034 *pass_size_in_words = TRUE;
5035 #ifdef GC_REDIRECT_TO_LOCAL
5036 return GC_local_gcj_fast_malloc;
5038 return GC_gcj_fast_malloc;
5043 return ves_icall_object_new_specific;
5047 * mono_object_new_from_token:
5048 * @image: Context where the type_token is hosted
5049 * @token: a token of the type that we want to create
5051 * Returns: A newly created object whose definition is
5052 * looked up using @token in the @image image
5055 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
5057 MONO_REQ_GC_UNSAFE_MODE;
5063 klass = mono_class_get_checked (image, token, &error);
5064 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
5066 result = mono_object_new_checked (domain, klass, &error);
5068 mono_error_raise_exception (&error); /* FIXME don't raise here */
5075 * mono_object_clone:
5076 * @obj: the object to clone
5078 * Returns: A newly created object who is a shallow copy of @obj
5081 mono_object_clone (MonoObject *obj)
5084 MonoObject *o = mono_object_clone_checked (obj, &error);
5085 mono_error_raise_exception (&error);
5091 mono_object_clone_checked (MonoObject *obj, MonoError *error)
5093 MONO_REQ_GC_UNSAFE_MODE;
5098 mono_error_init (error);
5100 size = obj->vtable->klass->instance_size;
5102 if (obj->vtable->klass->rank)
5103 return (MonoObject*)mono_array_clone ((MonoArray*)obj);
5105 o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
5107 if (G_UNLIKELY (!o)) {
5108 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5112 /* If the object doesn't contain references this will do a simple memmove. */
5113 mono_gc_wbarrier_object_copy (o, obj);
5115 if (obj->vtable->klass->has_finalize)
5116 mono_object_register_finalizer (o);
5121 * mono_array_full_copy:
5122 * @src: source array to copy
5123 * @dest: destination array
5125 * Copies the content of one array to another with exactly the same type and size.
5128 mono_array_full_copy (MonoArray *src, MonoArray *dest)
5130 MONO_REQ_GC_UNSAFE_MODE;
5133 MonoClass *klass = src->obj.vtable->klass;
5135 g_assert (klass == dest->obj.vtable->klass);
5137 size = mono_array_length (src);
5138 g_assert (size == mono_array_length (dest));
5139 size *= mono_array_element_size (klass);
5141 if (klass->element_class->valuetype) {
5142 if (klass->element_class->has_references)
5143 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
5145 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5147 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
5150 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5155 * mono_array_clone_in_domain:
5156 * @domain: the domain in which the array will be cloned into
5157 * @array: the array to clone
5159 * This routine returns a copy of the array that is hosted on the
5160 * specified MonoDomain.
5163 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
5165 MONO_REQ_GC_UNSAFE_MODE;
5171 MonoClass *klass = array->obj.vtable->klass;
5173 if (array->bounds == NULL) {
5174 size = mono_array_length (array);
5175 o = mono_array_new_full_checked (domain, klass, &size, NULL, &error);
5176 mono_error_raise_exception (&error); /* FIXME don't raise here */
5178 size *= mono_array_element_size (klass);
5180 if (klass->element_class->valuetype) {
5181 if (klass->element_class->has_references)
5182 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5184 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5186 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5189 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5194 sizes = (uintptr_t *)alloca (klass->rank * sizeof(intptr_t) * 2);
5195 size = mono_array_element_size (klass);
5196 for (i = 0; i < klass->rank; ++i) {
5197 sizes [i] = array->bounds [i].length;
5198 size *= array->bounds [i].length;
5199 sizes [i + klass->rank] = array->bounds [i].lower_bound;
5201 o = mono_array_new_full_checked (domain, klass, sizes, (intptr_t*)sizes + klass->rank, &error);
5202 mono_error_raise_exception (&error); /* FIXME don't raise here */
5204 if (klass->element_class->valuetype) {
5205 if (klass->element_class->has_references)
5206 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5208 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5210 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5213 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5221 * @array: the array to clone
5223 * Returns: A newly created array who is a shallow copy of @array
5226 mono_array_clone (MonoArray *array)
5228 MONO_REQ_GC_UNSAFE_MODE;
5230 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
5233 /* helper macros to check for overflow when calculating the size of arrays */
5234 #ifdef MONO_BIG_ARRAYS
5235 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
5236 #define MYGUINT_MAX MYGUINT64_MAX
5237 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5238 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
5239 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5240 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
5241 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
5243 #define MYGUINT32_MAX 4294967295U
5244 #define MYGUINT_MAX MYGUINT32_MAX
5245 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5246 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
5247 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5248 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
5249 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
5253 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
5255 MONO_REQ_GC_NEUTRAL_MODE;
5259 byte_len = mono_array_element_size (klass);
5260 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
5263 if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
5265 byte_len += MONO_SIZEOF_MONO_ARRAY;
5273 * mono_array_new_full:
5274 * @domain: domain where the object is created
5275 * @array_class: array class
5276 * @lengths: lengths for each dimension in the array
5277 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
5279 * This routine creates a new array objects with the given dimensions,
5280 * lower bounds and type.
5283 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
5286 MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
5287 mono_error_raise_exception (&error);
5293 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
5295 MONO_REQ_GC_UNSAFE_MODE;
5297 uintptr_t byte_len = 0, len, bounds_size;
5300 MonoArrayBounds *bounds;
5304 mono_error_init (error);
5306 if (!array_class->inited)
5307 mono_class_init (array_class);
5311 /* A single dimensional array with a 0 lower bound is the same as an szarray */
5312 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
5314 if (len > MONO_ARRAY_MAX_INDEX) {
5315 mono_error_set_generic_error (error, "System", "OverflowException", "");
5320 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
5322 for (i = 0; i < array_class->rank; ++i) {
5323 if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
5324 mono_error_set_generic_error (error, "System", "OverflowException", "");
5327 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5328 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5335 if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5336 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5342 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5343 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5346 byte_len = (byte_len + 3) & ~3;
5347 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5348 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5351 byte_len += bounds_size;
5354 * Following three lines almost taken from mono_object_new ():
5355 * they need to be kept in sync.
5357 vtable = mono_class_vtable_full (domain, array_class, TRUE);
5359 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5361 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5363 if (G_UNLIKELY (!o)) {
5364 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", byte_len);
5368 array = (MonoArray*)o;
5370 bounds = array->bounds;
5373 for (i = 0; i < array_class->rank; ++i) {
5374 bounds [i].length = lengths [i];
5376 bounds [i].lower_bound = lower_bounds [i];
5385 * @domain: domain where the object is created
5386 * @eclass: element class
5387 * @n: number of array elements
5389 * This routine creates a new szarray with @n elements of type @eclass.
5392 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5394 MONO_REQ_GC_UNSAFE_MODE;
5400 ac = mono_array_class_get (eclass, 1);
5403 arr = mono_array_new_specific_checked (mono_class_vtable_full (domain, ac, TRUE), n, &error);
5404 mono_error_raise_exception (&error); /* FIXME don't raise here */
5410 * mono_array_new_specific:
5411 * @vtable: a vtable in the appropriate domain for an initialized class
5412 * @n: number of array elements
5414 * This routine is a fast alternative to mono_array_new() for code which
5415 * can be sure about the domain it operates in.
5418 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5421 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5422 mono_error_raise_exception (&error); /* FIXME don't raise here */
5428 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
5430 MONO_REQ_GC_UNSAFE_MODE;
5435 mono_error_init (error);
5437 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
5438 mono_error_set_generic_error (error, "System", "OverflowException", "");
5442 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
5443 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5446 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
5448 if (G_UNLIKELY (!o)) {
5449 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", byte_len);
5453 return (MonoArray*)o;
5457 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
5460 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5461 mono_error_raise_exception (&error);
5467 * mono_string_new_utf16:
5468 * @text: a pointer to an utf16 string
5469 * @len: the length of the string
5471 * Returns: A newly created string object which contains @text.
5474 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
5476 MONO_REQ_GC_UNSAFE_MODE;
5479 MonoString *res = NULL;
5480 res = mono_string_new_utf16_checked (domain, text, len, &error);
5481 mono_error_raise_exception (&error);
5487 * mono_string_new_utf16_checked:
5488 * @text: a pointer to an utf16 string
5489 * @len: the length of the string
5490 * @error: written on error.
5492 * Returns: A newly created string object which contains @text.
5493 * On error, returns NULL and sets @error.
5496 mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
5498 MONO_REQ_GC_UNSAFE_MODE;
5502 mono_error_init (error);
5504 s = mono_string_new_size_checked (domain, len, error);
5506 memcpy (mono_string_chars (s), text, len * 2);
5512 * mono_string_new_utf32:
5513 * @text: a pointer to an utf32 string
5514 * @len: the length of the string
5516 * Returns: A newly created string object which contains @text.
5519 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
5521 MONO_REQ_GC_UNSAFE_MODE;
5525 mono_unichar2 *utf16_output = NULL;
5526 gint32 utf16_len = 0;
5527 GError *gerror = NULL;
5528 glong items_written;
5530 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
5533 g_error_free (gerror);
5535 while (utf16_output [utf16_len]) utf16_len++;
5537 s = mono_string_new_size_checked (domain, utf16_len, &error);
5538 mono_error_raise_exception (&error); /* FIXME don't raise here */
5540 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
5542 g_free (utf16_output);
5548 * mono_string_new_size:
5549 * @text: a pointer to an utf16 string
5550 * @len: the length of the string
5552 * Returns: A newly created string object of @len
5555 mono_string_new_size (MonoDomain *domain, gint32 len)
5558 MonoString *str = mono_string_new_size_checked (domain, len, &error);
5559 mono_error_raise_exception (&error);
5565 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
5567 MONO_REQ_GC_UNSAFE_MODE;
5573 mono_error_init (error);
5575 /* check for overflow */
5576 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
5577 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
5581 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
5582 g_assert (size > 0);
5584 vtable = mono_class_vtable (domain, mono_defaults.string_class);
5587 s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
5589 if (G_UNLIKELY (!s)) {
5590 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5598 * mono_string_new_len:
5599 * @text: a pointer to an utf8 string
5600 * @length: number of bytes in @text to consider
5602 * Returns: A newly created string object which contains @text.
5605 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
5607 MONO_REQ_GC_UNSAFE_MODE;
5610 GError *eg_error = NULL;
5611 MonoString *o = NULL;
5613 glong items_written;
5615 mono_error_init (&error);
5617 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
5620 o = mono_string_new_utf16_checked (domain, ut, items_written, &error);
5622 g_error_free (eg_error);
5626 mono_error_raise_exception (&error); /* FIXME don't raise here */
5632 * @text: a pointer to an utf8 string
5634 * Returns: A newly created string object which contains @text.
5636 * This function asserts if it cannot allocate a new string.
5638 * @deprecated Use mono_string_new_checked in new code.
5641 mono_string_new (MonoDomain *domain, const char *text)
5644 MonoString *res = NULL;
5645 res = mono_string_new_checked (domain, text, &error);
5646 mono_error_assert_ok (&error);
5651 * mono_string_new_checked:
5652 * @text: a pointer to an utf8 string
5653 * @merror: set on error
5655 * Returns: A newly created string object which contains @text.
5656 * On error returns NULL and sets @merror.
5659 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
5661 MONO_REQ_GC_UNSAFE_MODE;
5663 GError *eg_error = NULL;
5664 MonoString *o = NULL;
5666 glong items_written;
5669 mono_error_init (error);
5673 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &eg_error);
5676 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
5678 g_error_free (eg_error);
5681 mono_error_raise_exception (error);
5683 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
5688 MonoString *o = NULL;
5690 if (!g_utf8_validate (text, -1, &end)) {
5691 mono_error_set_argument (error, "text", "Not a valid utf8 string");
5695 len = g_utf8_strlen (text, -1);
5696 o = mono_string_new_size_checked (domain, len, error);
5699 str = mono_string_chars (o);
5701 while (text < end) {
5702 *str++ = g_utf8_get_char (text);
5703 text = g_utf8_next_char (text);
5712 * mono_string_new_wrapper:
5713 * @text: pointer to utf8 characters.
5715 * Helper function to create a string object from @text in the current domain.
5718 mono_string_new_wrapper (const char *text)
5720 MONO_REQ_GC_UNSAFE_MODE;
5722 MonoDomain *domain = mono_domain_get ();
5725 return mono_string_new (domain, text);
5732 * @class: the class of the value
5733 * @value: a pointer to the unboxed data
5735 * Returns: A newly created object which contains @value.
5738 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
5740 MONO_REQ_GC_UNSAFE_MODE;
5747 g_assert (klass->valuetype);
5748 if (mono_class_is_nullable (klass))
5749 return mono_nullable_box ((guint8 *)value, klass);
5751 vtable = mono_class_vtable (domain, klass);
5754 size = mono_class_instance_size (klass);
5755 res = mono_object_new_alloc_specific_checked (vtable, &error);
5756 mono_error_raise_exception (&error); /* FIXME don't raise here */
5758 size = size - sizeof (MonoObject);
5761 g_assert (size == mono_class_value_size (klass, NULL));
5762 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
5764 #if NO_UNALIGNED_ACCESS
5765 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5769 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
5772 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
5775 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
5778 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
5781 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5785 if (klass->has_finalize)
5786 mono_object_register_finalizer (res);
5792 * @dest: destination pointer
5793 * @src: source pointer
5794 * @klass: a valuetype class
5796 * Copy a valuetype from @src to @dest. This function must be used
5797 * when @klass contains references fields.
5800 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
5802 MONO_REQ_GC_UNSAFE_MODE;
5804 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
5808 * mono_value_copy_array:
5809 * @dest: destination array
5810 * @dest_idx: index in the @dest array
5811 * @src: source pointer
5812 * @count: number of items
5814 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
5815 * This function must be used when @klass contains references fields.
5816 * Overlap is handled.
5819 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
5821 MONO_REQ_GC_UNSAFE_MODE;
5823 int size = mono_array_element_size (dest->obj.vtable->klass);
5824 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
5825 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
5826 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
5830 * mono_object_get_domain:
5831 * @obj: object to query
5833 * Returns: the MonoDomain where the object is hosted
5836 mono_object_get_domain (MonoObject *obj)
5838 MONO_REQ_GC_UNSAFE_MODE;
5840 return mono_object_domain (obj);
5844 * mono_object_get_class:
5845 * @obj: object to query
5847 * Use this function to obtain the `MonoClass*` for a given `MonoObject`.
5849 * Returns: the MonoClass of the object.
5852 mono_object_get_class (MonoObject *obj)
5854 MONO_REQ_GC_UNSAFE_MODE;
5856 return mono_object_class (obj);
5859 * mono_object_get_size:
5860 * @o: object to query
5862 * Returns: the size, in bytes, of @o
5865 mono_object_get_size (MonoObject* o)
5867 MONO_REQ_GC_UNSAFE_MODE;
5869 MonoClass* klass = mono_object_class (o);
5870 if (klass == mono_defaults.string_class) {
5871 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
5872 } else if (o->vtable->rank) {
5873 MonoArray *array = (MonoArray*)o;
5874 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
5875 if (array->bounds) {
5878 size += sizeof (MonoArrayBounds) * o->vtable->rank;
5882 return mono_class_instance_size (klass);
5887 * mono_object_unbox:
5888 * @obj: object to unbox
5890 * Returns: a pointer to the start of the valuetype boxed in this
5893 * This method will assert if the object passed is not a valuetype.
5896 mono_object_unbox (MonoObject *obj)
5898 MONO_REQ_GC_UNSAFE_MODE;
5900 /* add assert for valuetypes? */
5901 g_assert (obj->vtable->klass->valuetype);
5902 return ((char*)obj) + sizeof (MonoObject);
5906 * mono_object_isinst:
5908 * @klass: a pointer to a class
5910 * Returns: @obj if @obj is derived from @klass
5913 mono_object_isinst (MonoObject *obj, MonoClass *klass)
5915 MONO_REQ_GC_UNSAFE_MODE;
5918 mono_class_init (klass);
5920 if (mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
5921 return mono_object_isinst_mbyref (obj, klass);
5926 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
5930 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
5932 MONO_REQ_GC_UNSAFE_MODE;
5942 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5943 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
5947 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
5948 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
5951 MonoClass *oklass = vt->klass;
5952 if (mono_class_is_transparent_proxy (oklass))
5953 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
5955 mono_class_setup_supertypes (klass);
5956 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
5959 #ifndef DISABLE_REMOTING
5960 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
5962 MonoDomain *domain = mono_domain_get ();
5964 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
5965 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
5966 MonoMethod *im = NULL;
5969 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
5971 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
5972 im = mono_object_get_virtual_method (rp, im);
5975 pa [0] = mono_type_get_object_checked (domain, &klass->byval_arg, &error);
5976 mono_error_raise_exception (&error); /* FIXME don't raise here */
5979 res = mono_runtime_invoke_checked (im, rp, pa, &error);
5980 mono_error_raise_exception (&error); /* FIXME don't raise here */
5982 if (*(MonoBoolean *) mono_object_unbox(res)) {
5983 /* Update the vtable of the remote type, so it can safely cast to this new type */
5984 mono_upgrade_remote_class (domain, obj, klass);
5988 #endif /* DISABLE_REMOTING */
5993 * mono_object_castclass_mbyref:
5995 * @klass: a pointer to a class
5997 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
6000 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
6002 MONO_REQ_GC_UNSAFE_MODE;
6004 if (!obj) return NULL;
6005 if (mono_object_isinst_mbyref (obj, klass)) return obj;
6007 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
6009 "InvalidCastException"));
6014 MonoDomain *orig_domain;
6020 str_lookup (MonoDomain *domain, gpointer user_data)
6022 MONO_REQ_GC_UNSAFE_MODE;
6024 LDStrInfo *info = (LDStrInfo *)user_data;
6025 if (info->res || domain == info->orig_domain)
6027 info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
6031 mono_string_get_pinned (MonoString *str, MonoError *error)
6033 MONO_REQ_GC_UNSAFE_MODE;
6035 mono_error_init (error);
6037 /* We only need to make a pinned version of a string if this is a moving GC */
6038 if (!mono_gc_is_moving ())
6042 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
6043 news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
6045 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
6046 news->length = mono_string_length (str);
6048 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6054 mono_string_is_interned_lookup (MonoString *str, int insert)
6056 MONO_REQ_GC_UNSAFE_MODE;
6059 MonoGHashTable *ldstr_table;
6060 MonoString *s, *res;
6063 domain = ((MonoObject *)str)->vtable->domain;
6064 ldstr_table = domain->ldstr_table;
6066 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6072 /* Allocate outside the lock */
6074 s = mono_string_get_pinned (str, &error);
6075 mono_error_raise_exception (&error); /* FIXME don't raise here */
6078 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6083 mono_g_hash_table_insert (ldstr_table, s, s);
6088 LDStrInfo ldstr_info;
6089 ldstr_info.orig_domain = domain;
6090 ldstr_info.ins = str;
6091 ldstr_info.res = NULL;
6093 mono_domain_foreach (str_lookup, &ldstr_info);
6094 if (ldstr_info.res) {
6096 * the string was already interned in some other domain:
6097 * intern it in the current one as well.
6099 mono_g_hash_table_insert (ldstr_table, str, str);
6109 * mono_string_is_interned:
6110 * @o: String to probe
6112 * Returns whether the string has been interned.
6115 mono_string_is_interned (MonoString *o)
6117 MONO_REQ_GC_UNSAFE_MODE;
6119 return mono_string_is_interned_lookup (o, FALSE);
6123 * mono_string_intern:
6124 * @o: String to intern
6126 * Interns the string passed.
6127 * Returns: The interned string.
6130 mono_string_intern (MonoString *str)
6132 MONO_REQ_GC_UNSAFE_MODE;
6134 return mono_string_is_interned_lookup (str, TRUE);
6139 * @domain: the domain where the string will be used.
6140 * @image: a metadata context
6141 * @idx: index into the user string table.
6143 * Implementation for the ldstr opcode.
6144 * Returns: a loaded string from the @image/@idx combination.
6147 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
6149 MONO_REQ_GC_UNSAFE_MODE;
6151 if (image->dynamic) {
6152 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
6155 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6156 return NULL; /*FIXME we should probably be raising an exception here*/
6157 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
6162 * mono_ldstr_metadata_sig
6163 * @domain: the domain for the string
6164 * @sig: the signature of a metadata string
6166 * Returns: a MonoString for a string stored in the metadata
6169 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
6171 MONO_REQ_GC_UNSAFE_MODE;
6174 const char *str = sig;
6175 MonoString *o, *interned;
6178 len2 = mono_metadata_decode_blob_size (str, &str);
6181 o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, &error);
6182 mono_error_raise_exception (&error); /* FIXME don't raise here */
6183 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
6186 guint16 *p2 = (guint16*)mono_string_chars (o);
6187 for (i = 0; i < len2; ++i) {
6188 *p2 = GUINT16_FROM_LE (*p2);
6194 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6197 return interned; /* o will get garbage collected */
6199 o = mono_string_get_pinned (o, &error);
6200 mono_error_raise_exception (&error); /* FIXME don't raise here */
6203 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6205 mono_g_hash_table_insert (domain->ldstr_table, o, o);
6215 * mono_string_to_utf8:
6216 * @s: a System.String
6218 * Returns the UTF8 representation for @s.
6219 * The resulting buffer needs to be freed with mono_free().
6221 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
6224 mono_string_to_utf8 (MonoString *s)
6226 MONO_REQ_GC_UNSAFE_MODE;
6229 char *result = mono_string_to_utf8_checked (s, &error);
6231 if (!mono_error_ok (&error))
6232 mono_error_raise_exception (&error);
6237 * mono_string_to_utf8_checked:
6238 * @s: a System.String
6239 * @error: a MonoError.
6241 * Converts a MonoString to its UTF8 representation. May fail; check
6242 * @error to determine whether the conversion was successful.
6243 * The resulting buffer should be freed with mono_free().
6246 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
6248 MONO_REQ_GC_UNSAFE_MODE;
6252 GError *gerror = NULL;
6254 mono_error_init (error);
6260 return g_strdup ("");
6262 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
6264 mono_error_set_argument (error, "string", "%s", gerror->message);
6265 g_error_free (gerror);
6268 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6269 if (s->length > written) {
6270 /* allocate the total length and copy the part of the string that has been converted */
6271 char *as2 = (char *)g_malloc0 (s->length);
6272 memcpy (as2, as, written);
6281 * mono_string_to_utf8_ignore:
6284 * Converts a MonoString to its UTF8 representation. Will ignore
6285 * invalid surrogate pairs.
6286 * The resulting buffer should be freed with mono_free().
6290 mono_string_to_utf8_ignore (MonoString *s)
6292 MONO_REQ_GC_UNSAFE_MODE;
6301 return g_strdup ("");
6303 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
6305 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6306 if (s->length > written) {
6307 /* allocate the total length and copy the part of the string that has been converted */
6308 char *as2 = (char *)g_malloc0 (s->length);
6309 memcpy (as2, as, written);
6318 * mono_string_to_utf8_image_ignore:
6319 * @s: a System.String
6321 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
6324 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
6326 MONO_REQ_GC_UNSAFE_MODE;
6328 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
6332 * mono_string_to_utf8_mp_ignore:
6333 * @s: a System.String
6335 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
6338 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
6340 MONO_REQ_GC_UNSAFE_MODE;
6342 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
6347 * mono_string_to_utf16:
6350 * Return an null-terminated array of the utf-16 chars
6351 * contained in @s. The result must be freed with g_free().
6352 * This is a temporary helper until our string implementation
6353 * is reworked to always include the null terminating char.
6356 mono_string_to_utf16 (MonoString *s)
6358 MONO_REQ_GC_UNSAFE_MODE;
6365 as = (char *)g_malloc ((s->length * 2) + 2);
6366 as [(s->length * 2)] = '\0';
6367 as [(s->length * 2) + 1] = '\0';
6370 return (gunichar2 *)(as);
6373 memcpy (as, mono_string_chars(s), s->length * 2);
6374 return (gunichar2 *)(as);
6378 * mono_string_to_utf32:
6381 * Return an null-terminated array of the UTF-32 (UCS-4) chars
6382 * contained in @s. The result must be freed with g_free().
6385 mono_string_to_utf32 (MonoString *s)
6387 MONO_REQ_GC_UNSAFE_MODE;
6389 mono_unichar4 *utf32_output = NULL;
6390 GError *error = NULL;
6391 glong items_written;
6396 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
6399 g_error_free (error);
6401 return utf32_output;
6405 * mono_string_from_utf16:
6406 * @data: the UTF16 string (LPWSTR) to convert
6408 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
6410 * Returns: a MonoString.
6413 mono_string_from_utf16 (gunichar2 *data)
6415 MONO_REQ_GC_UNSAFE_MODE;
6418 MonoString *res = NULL;
6419 MonoDomain *domain = mono_domain_get ();
6425 while (data [len]) len++;
6427 res = mono_string_new_utf16_checked (domain, data, len, &error);
6428 mono_error_raise_exception (&error); /* FIXME don't raise here */
6433 * mono_string_from_utf32:
6434 * @data: the UTF32 string (LPWSTR) to convert
6436 * Converts a UTF32 (UCS-4)to a MonoString.
6438 * Returns: a MonoString.
6441 mono_string_from_utf32 (mono_unichar4 *data)
6443 MONO_REQ_GC_UNSAFE_MODE;
6445 MonoString* result = NULL;
6446 mono_unichar2 *utf16_output = NULL;
6447 GError *error = NULL;
6448 glong items_written;
6454 while (data [len]) len++;
6456 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &error);
6459 g_error_free (error);
6461 result = mono_string_from_utf16 (utf16_output);
6462 g_free (utf16_output);
6467 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
6469 MONO_REQ_GC_UNSAFE_MODE;
6476 r = mono_string_to_utf8_ignore (s);
6478 r = mono_string_to_utf8_checked (s, error);
6479 if (!mono_error_ok (error))
6486 len = strlen (r) + 1;
6488 mp_s = (char *)mono_mempool_alloc (mp, len);
6490 mp_s = (char *)mono_image_alloc (image, len);
6492 memcpy (mp_s, r, len);
6500 * mono_string_to_utf8_image:
6501 * @s: a System.String
6503 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
6506 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
6508 MONO_REQ_GC_UNSAFE_MODE;
6510 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
6514 * mono_string_to_utf8_mp:
6515 * @s: a System.String
6517 * Same as mono_string_to_utf8, but allocate the string from a mempool.
6520 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
6522 MONO_REQ_GC_UNSAFE_MODE;
6524 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
6528 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
6531 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
6533 eh_callbacks = *cbs;
6536 MonoRuntimeExceptionHandlingCallbacks *
6537 mono_get_eh_callbacks (void)
6539 return &eh_callbacks;
6543 * mono_raise_exception:
6544 * @ex: exception object
6546 * Signal the runtime that the exception @ex has been raised in unmanaged code.
6549 mono_raise_exception (MonoException *ex)
6551 MONO_REQ_GC_UNSAFE_MODE;
6554 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
6555 * that will cause gcc to omit the function epilog, causing problems when
6556 * the JIT tries to walk the stack, since the return address on the stack
6557 * will point into the next function in the executable, not this one.
6559 eh_callbacks.mono_raise_exception (ex);
6563 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
6565 MONO_REQ_GC_UNSAFE_MODE;
6567 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
6571 * mono_wait_handle_new:
6572 * @domain: Domain where the object will be created
6573 * @handle: Handle for the wait handle
6575 * Returns: A new MonoWaitHandle created in the given domain for the given handle
6578 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
6580 MONO_REQ_GC_UNSAFE_MODE;
6583 MonoWaitHandle *res;
6584 gpointer params [1];
6585 static MonoMethod *handle_set;
6587 res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, &error);
6588 mono_error_raise_exception (&error); /* FIXME don't raise here */
6590 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
6592 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
6594 params [0] = &handle;
6596 mono_runtime_invoke_checked (handle_set, res, params, &error);
6597 mono_error_raise_exception (&error); /* FIXME don't raise here */
6603 mono_wait_handle_get_handle (MonoWaitHandle *handle)
6605 MONO_REQ_GC_UNSAFE_MODE;
6607 static MonoClassField *f_os_handle;
6608 static MonoClassField *f_safe_handle;
6610 if (!f_os_handle && !f_safe_handle) {
6611 f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
6612 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
6617 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
6621 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
6628 mono_runtime_capture_context (MonoDomain *domain)
6630 MONO_REQ_GC_UNSAFE_MODE;
6632 RuntimeInvokeFunction runtime_invoke;
6634 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
6635 MonoMethod *method = mono_get_context_capture_method ();
6636 MonoMethod *wrapper;
6639 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
6640 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
6641 domain->capture_context_method = mono_compile_method (method);
6644 runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
6646 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
6649 * mono_async_result_new:
6650 * @domain:domain where the object will be created.
6651 * @handle: wait handle.
6652 * @state: state to pass to AsyncResult
6653 * @data: C closure data.
6655 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
6656 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
6660 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
6662 MONO_REQ_GC_UNSAFE_MODE;
6665 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, &error);
6666 mono_error_raise_exception (&error); /* FIXME don't raise here */
6667 MonoObject *context = mono_runtime_capture_context (domain);
6668 /* we must capture the execution context from the original thread */
6670 MONO_OBJECT_SETREF (res, execution_context, context);
6671 /* note: result may be null if the flow is suppressed */
6674 res->data = (void **)data;
6675 MONO_OBJECT_SETREF (res, object_data, object_data);
6676 MONO_OBJECT_SETREF (res, async_state, state);
6678 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
6680 res->sync_completed = FALSE;
6681 res->completed = FALSE;
6687 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
6689 MONO_REQ_GC_UNSAFE_MODE;
6696 g_assert (ares->async_delegate);
6698 ac = (MonoAsyncCall*) ares->object_data;
6700 res = mono_runtime_delegate_invoke (ares->async_delegate, (void**) &ares->async_state, NULL);
6702 gpointer wait_event = NULL;
6704 ac->msg->exc = NULL;
6705 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args);
6706 MONO_OBJECT_SETREF (ac, res, res);
6708 mono_monitor_enter ((MonoObject*) ares);
6709 ares->completed = 1;
6711 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
6712 mono_monitor_exit ((MonoObject*) ares);
6714 if (wait_event != NULL)
6715 SetEvent (wait_event);
6717 if (ac->cb_method) {
6718 mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
6719 mono_error_raise_exception (&error);
6727 mono_message_init (MonoDomain *domain,
6728 MonoMethodMessage *this_obj,
6729 MonoReflectionMethod *method,
6730 MonoArray *out_args)
6732 MONO_REQ_GC_UNSAFE_MODE;
6734 static MonoClass *object_array_klass;
6735 static MonoClass *byte_array_klass;
6736 static MonoClass *string_array_klass;
6738 MonoMethodSignature *sig = mono_method_signature (method->method);
6745 if (!object_array_klass) {
6748 klass = mono_array_class_get (mono_defaults.byte_class, 1);
6750 byte_array_klass = klass;
6752 klass = mono_array_class_get (mono_defaults.string_class, 1);
6754 string_array_klass = klass;
6756 klass = mono_array_class_get (mono_defaults.object_class, 1);
6759 mono_atomic_store_release (&object_array_klass, klass);
6762 MONO_OBJECT_SETREF (this_obj, method, method);
6764 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), sig->param_count, &error);
6765 mono_error_raise_exception (&error); /* FIXME don't raise here */
6767 MONO_OBJECT_SETREF (this_obj, args, arr);
6769 arr = mono_array_new_specific_checked (mono_class_vtable (domain, byte_array_klass), sig->param_count, &error);
6770 mono_error_raise_exception (&error); /* FIXME don't raise here */
6772 MONO_OBJECT_SETREF (this_obj, arg_types, arr);
6774 this_obj->async_result = NULL;
6775 this_obj->call_type = CallType_Sync;
6777 names = g_new (char *, sig->param_count);
6778 mono_method_get_param_names (method->method, (const char **) names);
6780 arr = mono_array_new_specific_checked (mono_class_vtable (domain, string_array_klass), sig->param_count, &error);
6781 mono_error_raise_exception (&error); /* FIXME don't raise here */
6783 MONO_OBJECT_SETREF (this_obj, names, arr);
6785 for (i = 0; i < sig->param_count; i++) {
6786 name = mono_string_new (domain, names [i]);
6787 mono_array_setref (this_obj->names, i, name);
6791 for (i = 0, j = 0; i < sig->param_count; i++) {
6792 if (sig->params [i]->byref) {
6794 MonoObject* arg = (MonoObject *)mono_array_get (out_args, gpointer, j);
6795 mono_array_setref (this_obj->args, i, arg);
6799 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
6803 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
6806 mono_array_set (this_obj->arg_types, guint8, i, arg_type);
6810 #ifndef DISABLE_REMOTING
6812 * mono_remoting_invoke:
6813 * @real_proxy: pointer to a RealProxy object
6814 * @msg: The MonoMethodMessage to execute
6815 * @exc: used to store exceptions
6816 * @out_args: used to store output arguments
6818 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
6819 * IMessage interface and it is not trivial to extract results from there. So
6820 * we call an helper method PrivateInvoke instead of calling
6821 * RealProxy::Invoke() directly.
6823 * Returns: the result object.
6826 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
6827 MonoObject **exc, MonoArray **out_args)
6829 MONO_REQ_GC_UNSAFE_MODE;
6833 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
6836 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
6839 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
6841 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6842 real_proxy->vtable->domain->private_invoke_method = im;
6845 pa [0] = real_proxy;
6851 o = mono_runtime_try_invoke (im, NULL, pa, exc, &error);
6853 o = mono_runtime_invoke_checked (im, NULL, pa, &error);
6855 mono_error_raise_exception (&error); /* FIXME don't raise here */
6862 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
6863 MonoObject **exc, MonoArray **out_args)
6865 MONO_REQ_GC_UNSAFE_MODE;
6867 static MonoClass *object_array_klass;
6871 MonoMethodSignature *sig;
6874 int i, j, outarg_count = 0;
6876 #ifndef DISABLE_REMOTING
6877 if (target && mono_object_is_transparent_proxy (target)) {
6878 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
6879 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6880 target = tp->rp->unwrapped_server;
6882 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
6887 domain = mono_domain_get ();
6888 method = msg->method->method;
6889 sig = mono_method_signature (method);
6891 for (i = 0; i < sig->param_count; i++) {
6892 if (sig->params [i]->byref)
6896 if (!object_array_klass) {
6899 klass = mono_array_class_get (mono_defaults.object_class, 1);
6902 mono_memory_barrier ();
6903 object_array_klass = klass;
6906 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, &error);
6907 mono_error_raise_exception (&error); /* FIXME don't raise here */
6909 mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
6912 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
6914 for (i = 0, j = 0; i < sig->param_count; i++) {
6915 if (sig->params [i]->byref) {
6917 arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
6918 mono_array_setref (*out_args, j, arg);
6927 * mono_object_to_string:
6929 * @exc: Any exception thrown by ToString (). May be NULL.
6931 * Returns: the result of calling ToString () on an object.
6934 mono_object_to_string (MonoObject *obj, MonoObject **exc)
6936 MONO_REQ_GC_UNSAFE_MODE;
6938 static MonoMethod *to_string = NULL;
6947 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
6949 method = mono_object_get_virtual_method (obj, to_string);
6951 // Unbox value type if needed
6952 if (mono_class_is_valuetype (mono_method_get_class (method))) {
6953 target = mono_object_unbox (obj);
6957 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
6958 if (*exc == NULL && !mono_error_ok (&error))
6959 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
6961 mono_error_cleanup (&error);
6963 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
6964 mono_error_raise_exception (&error); /* FIXME don't raise here */
6971 * mono_print_unhandled_exception:
6972 * @exc: The exception
6974 * Prints the unhandled exception.
6977 mono_print_unhandled_exception (MonoObject *exc)
6979 MONO_REQ_GC_UNSAFE_MODE;
6982 char *message = (char*)"";
6983 gboolean free_message = FALSE;
6986 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
6987 message = g_strdup ("OutOfMemoryException");
6988 free_message = TRUE;
6989 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
6990 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
6991 free_message = TRUE;
6994 if (((MonoException*)exc)->native_trace_ips) {
6995 message = mono_exception_get_native_backtrace ((MonoException*)exc);
6996 free_message = TRUE;
6998 MonoObject *other_exc = NULL;
6999 str = mono_object_to_string (exc, &other_exc);
7001 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
7002 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
7004 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
7005 original_backtrace, nested_backtrace);
7007 g_free (original_backtrace);
7008 g_free (nested_backtrace);
7009 free_message = TRUE;
7011 message = mono_string_to_utf8_checked (str, &error);
7012 if (!mono_error_ok (&error)) {
7013 mono_error_cleanup (&error);
7014 message = (char *) "";
7016 free_message = TRUE;
7023 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
7024 * exc->vtable->klass->name, message);
7026 g_printerr ("\nUnhandled Exception:\n%s\n", message);
7033 * mono_delegate_ctor:
7034 * @this: pointer to an uninitialized delegate object
7035 * @target: target object
7036 * @addr: pointer to native code
7039 * Initialize a delegate and sets a specific method, not the one
7040 * associated with addr. This is useful when sharing generic code.
7041 * In that case addr will most probably not be associated with the
7042 * correct instantiation of the method.
7045 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method)
7047 MONO_REQ_GC_UNSAFE_MODE;
7049 MonoDelegate *delegate = (MonoDelegate *)this_obj;
7051 g_assert (this_obj);
7054 g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
7057 delegate->method = method;
7059 mono_stats.delegate_creations++;
7061 #ifndef DISABLE_REMOTING
7062 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
7064 method = mono_marshal_get_remoting_invoke (method);
7065 delegate->method_ptr = mono_compile_method (method);
7066 MONO_OBJECT_SETREF (delegate, target, target);
7070 delegate->method_ptr = addr;
7071 MONO_OBJECT_SETREF (delegate, target, target);
7074 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
7075 if (callbacks.init_delegate)
7076 callbacks.init_delegate (delegate);
7080 * mono_delegate_ctor:
7081 * @this: pointer to an uninitialized delegate object
7082 * @target: target object
7083 * @addr: pointer to native code
7085 * This is used to initialize a delegate.
7088 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr)
7090 MONO_REQ_GC_UNSAFE_MODE;
7092 MonoDomain *domain = mono_domain_get ();
7094 MonoMethod *method = NULL;
7098 ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
7100 if (!ji && domain != mono_get_root_domain ())
7101 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
7103 method = mono_jit_info_get_method (ji);
7104 g_assert (!method->klass->generic_container);
7107 mono_delegate_ctor_with_method (this_obj, target, addr, method);
7111 * mono_method_call_message_new:
7112 * @method: method to encapsulate
7113 * @params: parameters to the method
7114 * @invoke: optional, delegate invoke.
7115 * @cb: async callback delegate.
7116 * @state: state passed to the async callback.
7118 * Translates arguments pointers into a MonoMethodMessage.
7121 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
7122 MonoDelegate **cb, MonoObject **state)
7124 MONO_REQ_GC_UNSAFE_MODE;
7128 MonoDomain *domain = mono_domain_get ();
7129 MonoMethodSignature *sig = mono_method_signature (method);
7130 MonoMethodMessage *msg;
7133 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7134 mono_error_raise_exception (&error); /* FIXME don't raise here */
7137 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, &error);
7138 mono_error_raise_exception (&error); /* FIXME don't raise here */
7139 mono_message_init (domain, msg, rm, NULL);
7140 count = sig->param_count - 2;
7142 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, &error);
7143 mono_error_raise_exception (&error); /* FIXME don't raise here */
7144 mono_message_init (domain, msg, rm, NULL);
7145 count = sig->param_count;
7148 for (i = 0; i < count; i++) {
7153 if (sig->params [i]->byref)
7154 vpos = *((gpointer *)params [i]);
7158 klass = mono_class_from_mono_type (sig->params [i]);
7160 if (klass->valuetype)
7161 arg = mono_value_box (domain, klass, vpos);
7163 arg = *((MonoObject **)vpos);
7165 mono_array_setref (msg->args, i, arg);
7168 if (cb != NULL && state != NULL) {
7169 *cb = *((MonoDelegate **)params [i]);
7171 *state = *((MonoObject **)params [i]);
7178 * mono_method_return_message_restore:
7180 * Restore results from message based processing back to arguments pointers
7183 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
7185 MONO_REQ_GC_UNSAFE_MODE;
7187 MonoMethodSignature *sig = mono_method_signature (method);
7188 int i, j, type, size, out_len;
7190 if (out_args == NULL)
7192 out_len = mono_array_length (out_args);
7196 for (i = 0, j = 0; i < sig->param_count; i++) {
7197 MonoType *pt = sig->params [i];
7202 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
7204 arg = (char *)mono_array_get (out_args, gpointer, j);
7207 g_assert (type != MONO_TYPE_VOID);
7209 if (MONO_TYPE_IS_REFERENCE (pt)) {
7210 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
7213 MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
7214 size = mono_class_value_size (klass, NULL);
7215 if (klass->has_references)
7216 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
7218 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
7220 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
7221 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
7230 #ifndef DISABLE_REMOTING
7233 * mono_load_remote_field:
7234 * @this: pointer to an object
7235 * @klass: klass of the object containing @field
7236 * @field: the field to load
7237 * @res: a storage to store the result
7239 * This method is called by the runtime on attempts to load fields of
7240 * transparent proxy objects. @this points to such TP, @klass is the class of
7241 * the object containing @field. @res is a storage location which can be
7242 * used to store the result.
7244 * Returns: an address pointing to the value of field.
7247 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
7249 MONO_REQ_GC_UNSAFE_MODE;
7253 static MonoMethod *getter = NULL;
7254 MonoDomain *domain = mono_domain_get ();
7255 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7256 MonoClass *field_class;
7257 MonoMethodMessage *msg;
7258 MonoArray *out_args;
7262 g_assert (mono_object_is_transparent_proxy (this_obj));
7263 g_assert (res != NULL);
7265 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7266 mono_field_get_value (tp->rp->unwrapped_server, field, res);
7271 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
7273 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7276 field_class = mono_class_from_mono_type (field->type);
7278 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7279 mono_error_raise_exception (&error); /* FIXME don't raise here */
7280 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
7281 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, &error);
7282 mono_error_raise_exception (&error); /* FIXME don't raise here */
7283 mono_message_init (domain, msg, rm, out_args);
7285 full_name = mono_type_get_full_name (klass);
7286 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7287 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7290 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
7292 if (exc) mono_raise_exception ((MonoException *)exc);
7294 if (mono_array_length (out_args) == 0)
7297 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
7299 if (field_class->valuetype) {
7300 return ((char *)*res) + sizeof (MonoObject);
7306 * mono_load_remote_field_new:
7311 * Missing documentation.
7314 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
7316 MONO_REQ_GC_UNSAFE_MODE;
7320 static MonoMethod *getter = NULL;
7321 MonoDomain *domain = mono_domain_get ();
7322 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7323 MonoClass *field_class;
7324 MonoMethodMessage *msg;
7325 MonoArray *out_args;
7326 MonoObject *exc, *res;
7329 g_assert (mono_object_is_transparent_proxy (this_obj));
7331 field_class = mono_class_from_mono_type (field->type);
7333 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7335 if (field_class->valuetype) {
7336 res = mono_object_new_checked (domain, field_class, &error);
7337 mono_error_raise_exception (&error); /* FIXME don't raise here */
7338 val = ((gchar *) res) + sizeof (MonoObject);
7342 mono_field_get_value (tp->rp->unwrapped_server, field, val);
7347 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
7349 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7352 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7353 mono_error_raise_exception (&error); /* FIXME don't raise here */
7354 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
7356 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, &error);
7357 mono_error_raise_exception (&error); /* FIXME don't raise here */
7358 mono_message_init (domain, msg, rm, out_args);
7360 full_name = mono_type_get_full_name (klass);
7361 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7362 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7365 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
7367 if (exc) mono_raise_exception ((MonoException *)exc);
7369 if (mono_array_length (out_args) == 0)
7372 res = mono_array_get (out_args, MonoObject *, 0);
7378 * mono_store_remote_field:
7379 * @this_obj: pointer to an object
7380 * @klass: klass of the object containing @field
7381 * @field: the field to load
7382 * @val: the value/object to store
7384 * This method is called by the runtime on attempts to store fields of
7385 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
7386 * the object containing @field. @val is the new value to store in @field.
7389 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
7391 MONO_REQ_GC_UNSAFE_MODE;
7395 static MonoMethod *setter = NULL;
7396 MonoDomain *domain = mono_domain_get ();
7397 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7398 MonoClass *field_class;
7399 MonoMethodMessage *msg;
7400 MonoArray *out_args;
7405 g_assert (mono_object_is_transparent_proxy (this_obj));
7407 field_class = mono_class_from_mono_type (field->type);
7409 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7410 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
7411 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
7416 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
7418 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7421 if (field_class->valuetype)
7422 arg = mono_value_box (domain, field_class, val);
7424 arg = *((MonoObject **)val);
7427 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7428 mono_error_raise_exception (&error); /* FIXME don't raise here */
7429 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, setter, NULL, &error);
7430 mono_error_raise_exception (&error); /* FIXME don't raise here */
7431 mono_message_init (domain, msg, rm, NULL);
7433 full_name = mono_type_get_full_name (klass);
7434 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7435 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7436 mono_array_setref (msg->args, 2, arg);
7439 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
7441 if (exc) mono_raise_exception ((MonoException *)exc);
7445 * mono_store_remote_field_new:
7451 * Missing documentation
7454 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
7456 MONO_REQ_GC_UNSAFE_MODE;
7460 static MonoMethod *setter = NULL;
7461 MonoDomain *domain = mono_domain_get ();
7462 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7463 MonoClass *field_class;
7464 MonoMethodMessage *msg;
7465 MonoArray *out_args;
7469 g_assert (mono_object_is_transparent_proxy (this_obj));
7471 field_class = mono_class_from_mono_type (field->type);
7473 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7474 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
7475 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
7480 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
7482 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7485 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7486 mono_error_raise_exception (&error); /* FIXME don't raise here */
7487 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, setter, NULL, &error);
7488 mono_error_raise_exception (&error); /* FIXME don't raise here */
7489 mono_message_init (domain, msg, rm, NULL);
7491 full_name = mono_type_get_full_name (klass);
7492 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7493 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7494 mono_array_setref (msg->args, 2, arg);
7497 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
7499 if (exc) mono_raise_exception ((MonoException *)exc);
7504 * mono_create_ftnptr:
7506 * Given a function address, create a function descriptor for it.
7507 * This is only needed on some platforms.
7510 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
7512 return callbacks.create_ftnptr (domain, addr);
7516 * mono_get_addr_from_ftnptr:
7518 * Given a pointer to a function descriptor, return the function address.
7519 * This is only needed on some platforms.
7522 mono_get_addr_from_ftnptr (gpointer descr)
7524 return callbacks.get_addr_from_ftnptr (descr);
7528 * mono_string_chars:
7531 * Returns a pointer to the UCS16 characters stored in the MonoString
7534 mono_string_chars (MonoString *s)
7536 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
7542 * mono_string_length:
7545 * Returns the lenght in characters of the string
7548 mono_string_length (MonoString *s)
7550 MONO_REQ_GC_UNSAFE_MODE;
7556 * mono_array_length:
7557 * @array: a MonoArray*
7559 * Returns the total number of elements in the array. This works for
7560 * both vectors and multidimensional arrays.
7563 mono_array_length (MonoArray *array)
7565 MONO_REQ_GC_UNSAFE_MODE;
7567 return array->max_length;
7571 * mono_array_addr_with_size:
7572 * @array: a MonoArray*
7573 * @size: size of the array elements
7574 * @idx: index into the array
7576 * Use this function to obtain the address for the @idx item on the
7577 * @array containing elements of size @size.
7579 * This method performs no bounds checking or type checking.
7581 * Returns the address of the @idx element in the array.
7584 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
7586 MONO_REQ_GC_UNSAFE_MODE;
7588 return ((char*)(array)->vector) + size * idx;
7593 mono_glist_to_array (GList *list, MonoClass *eclass)
7595 MonoDomain *domain = mono_domain_get ();
7602 len = g_list_length (list);
7603 res = mono_array_new (domain, eclass, len);
7605 for (i = 0; list; list = list->next, i++)
7606 mono_array_set (res, gpointer, i, list->data);
7613 * The following section is purely to declare prototypes and
7614 * document the API, as these C files are processed by our
7620 * @array: array to alter
7621 * @element_type: A C type name, this macro will use the sizeof(type) to determine the element size
7622 * @index: index into the array
7623 * @value: value to set
7625 * Value Type version: This sets the @index's element of the @array
7626 * with elements of size sizeof(type) to the provided @value.
7628 * This macro does not attempt to perform type checking or bounds checking.
7630 * Use this to set value types in a `MonoArray`.
7632 void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
7637 * mono_array_setref:
7638 * @array: array to alter
7639 * @index: index into the array
7640 * @value: value to set
7642 * Reference Type version: This sets the @index's element of the
7643 * @array with elements of size sizeof(type) to the provided @value.
7645 * This macro does not attempt to perform type checking or bounds checking.
7647 * Use this to reference types in a `MonoArray`.
7649 void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
7655 * @array: array on which to operate on
7656 * @element_type: C element type (example: MonoString *, int, MonoObject *)
7657 * @index: index into the array
7659 * Use this macro to retrieve the @index element of an @array and
7660 * extract the value assuming that the elements of the array match
7661 * the provided type value.
7663 * This method can be used with both arrays holding value types and
7664 * reference types. For reference types, the @type parameter should
7665 * be a `MonoObject*` or any subclass of it, like `MonoString*`.
7667 * This macro does not attempt to perform type checking or bounds checking.
7669 * Returns: The element at the @index position in the @array.
7671 Type mono_array_get (MonoArray *array, Type element_type, uintptr_t index)