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-internal.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-internal.h>
40 #include <mono/metadata/verify-internals.h>
41 #include <mono/utils/strenc.h>
42 #include <mono/utils/mono-counters.h>
43 #include <mono/utils/mono-error-internals.h>
44 #include <mono/utils/mono-memory-model.h>
45 #include <mono/utils/checked-build.h>
46 #include "cominterop.h"
49 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value);
52 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig);
55 free_main_args (void);
58 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error);
61 #define ldstr_lock() mono_mutex_lock (&ldstr_section)
62 #define ldstr_unlock() mono_mutex_unlock (&ldstr_section)
63 static mono_mutex_t ldstr_section;
66 mono_runtime_object_init (MonoObject *this)
68 MONO_REQ_GC_UNSAFE_MODE;
70 MonoMethod *method = NULL;
71 MonoClass *klass = this->vtable->klass;
73 method = mono_class_get_method_from_name (klass, ".ctor", 0);
75 g_error ("Could not lookup zero argument constructor for class %s", mono_type_get_full_name (klass));
77 if (method->klass->valuetype)
78 this = mono_object_unbox (this);
79 mono_runtime_invoke (method, this, NULL, NULL);
82 /* The pseudo algorithm for type initialization from the spec
83 Note it doesn't say anything about domains - only threads.
85 2. If the type is initialized you are done.
86 2.1. If the type is not yet initialized, try to take an
88 2.2. If successful, record this thread as responsible for
89 initializing the type and proceed to step 2.3.
90 2.2.1. If not, see whether this thread or any thread
91 waiting for this thread to complete already holds the lock.
92 2.2.2. If so, return since blocking would create a deadlock. This thread
93 will now see an incompletely initialized state for the type,
94 but no deadlock will arise.
95 2.2.3 If not, block until the type is initialized then return.
96 2.3 Initialize the parent type and then all interfaces implemented
98 2.4 Execute the type initialization code for this type.
99 2.5 Mark the type as initialized, release the initialization lock,
100 awaken any threads waiting for this type to be initialized,
107 guint32 initializing_tid;
108 guint32 waiting_count;
110 mono_mutex_t initialization_section;
111 } TypeInitializationLock;
113 /* for locking access to type_initialization_hash and blocked_thread_hash */
114 static mono_mutex_t type_initialization_section;
117 mono_type_initialization_lock (void)
119 /* The critical sections protected by this lock in mono_runtime_class_init_full () can block */
120 MONO_PREPARE_BLOCKING;
121 mono_mutex_lock (&type_initialization_section);
122 MONO_FINISH_BLOCKING;
126 mono_type_initialization_unlock (void)
128 mono_mutex_unlock (&type_initialization_section);
132 mono_type_init_lock (TypeInitializationLock *lock)
134 MONO_REQ_GC_NEUTRAL_MODE;
137 mono_mutex_lock (&lock->initialization_section);
138 MONO_FINISH_TRY_BLOCKING;
142 mono_type_init_unlock (TypeInitializationLock *lock)
144 mono_mutex_unlock (&lock->initialization_section);
147 /* from vtable to lock */
148 static GHashTable *type_initialization_hash;
150 /* from thread id to thread id being waited on */
151 static GHashTable *blocked_thread_hash;
154 static MonoThread *main_thread;
156 /* Functions supplied by the runtime */
157 static MonoRuntimeCallbacks callbacks;
160 * mono_thread_set_main:
161 * @thread: thread to set as the main thread
163 * This function can be used to instruct the runtime to treat @thread
164 * as the main thread, ie, the thread that would normally execute the Main()
165 * method. This basically means that at the end of @thread, the runtime will
166 * wait for the existing foreground threads to quit and other such details.
169 mono_thread_set_main (MonoThread *thread)
171 MONO_REQ_GC_UNSAFE_MODE;
173 static gboolean registered = FALSE;
176 MONO_GC_REGISTER_ROOT_SINGLE (main_thread, MONO_ROOT_SOURCE_THREADING, "main thread object");
180 main_thread = thread;
184 mono_thread_get_main (void)
186 MONO_REQ_GC_UNSAFE_MODE;
192 mono_type_initialization_init (void)
194 mono_mutex_init_recursive (&type_initialization_section);
195 type_initialization_hash = g_hash_table_new (NULL, NULL);
196 blocked_thread_hash = g_hash_table_new (NULL, NULL);
197 mono_mutex_init_recursive (&ldstr_section);
201 mono_type_initialization_cleanup (void)
204 /* This is causing race conditions with
205 * mono_release_type_locks
207 mono_mutex_destroy (&type_initialization_section);
208 g_hash_table_destroy (type_initialization_hash);
209 type_initialization_hash = NULL;
211 mono_mutex_destroy (&ldstr_section);
212 g_hash_table_destroy (blocked_thread_hash);
213 blocked_thread_hash = NULL;
219 * get_type_init_exception_for_vtable:
221 * Return the stored type initialization exception for VTABLE.
223 static MonoException*
224 get_type_init_exception_for_vtable (MonoVTable *vtable)
226 MONO_REQ_GC_UNSAFE_MODE;
228 MonoDomain *domain = vtable->domain;
229 MonoClass *klass = vtable->klass;
233 if (!vtable->init_failed)
234 g_error ("Trying to get the init exception for a non-failed vtable of class %s", mono_type_get_full_name (klass));
237 * If the initializing thread was rudely aborted, the exception is not stored
241 mono_domain_lock (domain);
242 if (domain->type_init_exception_hash)
243 ex = mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
244 mono_domain_unlock (domain);
247 if (klass->name_space && *klass->name_space)
248 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
250 full_name = g_strdup (klass->name);
251 ex = mono_get_exception_type_initialization (full_name, NULL);
258 * mono_runtime_class_init:
259 * @vtable: vtable that needs to be initialized
261 * This routine calls the class constructor for @vtable.
264 mono_runtime_class_init (MonoVTable *vtable)
266 MONO_REQ_GC_UNSAFE_MODE;
268 mono_runtime_class_init_full (vtable, TRUE);
272 * mono_runtime_class_init_full:
273 * @vtable that neeeds to be initialized
274 * @raise_exception is TRUE, exceptions are raised intead of returned
278 mono_runtime_class_init_full (MonoVTable *vtable, gboolean raise_exception)
280 MONO_REQ_GC_UNSAFE_MODE;
283 MonoException *exc_to_throw;
284 MonoMethod *method = NULL;
287 MonoDomain *domain = vtable->domain;
288 TypeInitializationLock *lock;
290 int do_initialization = 0;
291 MonoDomain *last_domain = NULL;
293 if (vtable->initialized)
297 klass = vtable->klass;
299 if (!klass->image->checked_module_cctor) {
300 mono_image_check_for_module_cctor (klass->image);
301 if (klass->image->has_module_cctor) {
303 MonoClass *module_klass;
304 MonoVTable *module_vtable;
306 module_klass = mono_class_get_checked (klass->image, MONO_TOKEN_TYPE_DEF | 1, &error);
308 exc = mono_error_convert_to_exception (&error);
310 mono_raise_exception (exc);
314 module_vtable = mono_class_vtable_full (vtable->domain, module_klass, raise_exception);
317 exc = mono_runtime_class_init_full (module_vtable, raise_exception);
322 method = mono_class_get_cctor (klass);
324 vtable->initialized = 1;
328 tid = GetCurrentThreadId ();
330 mono_type_initialization_lock ();
331 /* double check... */
332 if (vtable->initialized) {
333 mono_type_initialization_unlock ();
336 if (vtable->init_failed) {
337 mono_type_initialization_unlock ();
339 /* The type initialization already failed once, rethrow the same exception */
341 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
342 return get_type_init_exception_for_vtable (vtable);
344 lock = g_hash_table_lookup (type_initialization_hash, vtable);
346 /* This thread will get to do the initialization */
347 if (mono_domain_get () != domain) {
348 /* Transfer into the target domain */
349 last_domain = mono_domain_get ();
350 if (!mono_domain_set (domain, FALSE)) {
351 vtable->initialized = 1;
352 mono_type_initialization_unlock ();
354 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
355 return mono_get_exception_appdomain_unloaded ();
358 lock = g_malloc (sizeof(TypeInitializationLock));
359 mono_mutex_init_recursive (&lock->initialization_section);
360 lock->initializing_tid = tid;
361 lock->waiting_count = 1;
363 /* grab the vtable lock while this thread still owns type_initialization_section */
364 /* This is why type_initialization_lock needs to enter blocking mode */
365 mono_type_init_lock (lock);
366 g_hash_table_insert (type_initialization_hash, vtable, lock);
367 do_initialization = 1;
370 TypeInitializationLock *pending_lock;
372 if (lock->initializing_tid == tid || lock->done) {
373 mono_type_initialization_unlock ();
376 /* see if the thread doing the initialization is already blocked on this thread */
377 blocked = GUINT_TO_POINTER (lock->initializing_tid);
378 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
379 if (pending_lock->initializing_tid == tid) {
380 if (!pending_lock->done) {
381 mono_type_initialization_unlock ();
384 /* the thread doing the initialization is blocked on this thread,
385 but on a lock that has already been freed. It just hasn't got
390 blocked = GUINT_TO_POINTER (pending_lock->initializing_tid);
392 ++lock->waiting_count;
393 /* record the fact that we are waiting on the initializing thread */
394 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
396 mono_type_initialization_unlock ();
398 if (do_initialization) {
399 mono_runtime_invoke (method, NULL, NULL, (MonoObject **) &exc);
401 /* If the initialization failed, mark the class as unusable. */
402 /* Avoid infinite loops */
404 (klass->image == mono_defaults.corlib &&
405 !strcmp (klass->name_space, "System") &&
406 !strcmp (klass->name, "TypeInitializationException")))) {
407 vtable->init_failed = 1;
409 if (klass->name_space && *klass->name_space)
410 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
412 full_name = g_strdup (klass->name);
413 exc_to_throw = mono_get_exception_type_initialization (full_name, exc);
417 * Store the exception object so it could be thrown on subsequent
420 mono_domain_lock (domain);
421 if (!domain->type_init_exception_hash)
422 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");
423 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
424 mono_domain_unlock (domain);
428 mono_domain_set (last_domain, TRUE);
430 mono_type_init_unlock (lock);
432 /* this just blocks until the initializing thread is done */
433 mono_type_init_lock (lock);
434 mono_type_init_unlock (lock);
437 mono_type_initialization_lock ();
438 if (lock->initializing_tid != tid)
439 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
440 --lock->waiting_count;
441 if (lock->waiting_count == 0) {
442 mono_mutex_destroy (&lock->initialization_section);
443 g_hash_table_remove (type_initialization_hash, vtable);
446 mono_memory_barrier ();
447 if (!vtable->init_failed)
448 vtable->initialized = 1;
449 mono_type_initialization_unlock ();
451 if (vtable->init_failed) {
452 /* Either we were the initializing thread or we waited for the initialization */
454 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
455 return get_type_init_exception_for_vtable (vtable);
461 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
463 MONO_REQ_GC_NEUTRAL_MODE;
465 MonoVTable *vtable = (MonoVTable*)key;
467 TypeInitializationLock *lock = (TypeInitializationLock*) value;
468 if (lock->initializing_tid == GPOINTER_TO_UINT (user) && !lock->done) {
471 * Have to set this since it cannot be set by the normal code in
472 * mono_runtime_class_init (). In this case, the exception object is not stored,
473 * and get_type_init_exception_for_class () needs to be aware of this.
475 vtable->init_failed = 1;
476 mono_type_init_unlock (lock);
477 --lock->waiting_count;
478 if (lock->waiting_count == 0) {
479 mono_mutex_destroy (&lock->initialization_section);
488 mono_release_type_locks (MonoInternalThread *thread)
490 MONO_REQ_GC_UNSAFE_MODE;
492 mono_type_initialization_lock ();
493 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, (gpointer)(gsize)(thread->tid));
494 mono_type_initialization_unlock ();
498 default_trampoline (MonoMethod *method)
504 default_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
506 g_assert_not_reached ();
511 #ifndef DISABLE_REMOTING
514 default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target)
516 g_error ("remoting not installed");
520 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
524 default_delegate_trampoline (MonoDomain *domain, MonoClass *klass)
526 g_assert_not_reached ();
530 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
531 static MonoJumpTrampoline arch_create_jump_trampoline = default_jump_trampoline;
532 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
533 static MonoImtThunkBuilder imt_thunk_builder;
534 #if (MONO_IMT_SIZE > 32)
535 #error "MONO_IMT_SIZE cannot be larger than 32"
539 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
541 memcpy (&callbacks, cbs, sizeof (*cbs));
544 MonoRuntimeCallbacks*
545 mono_get_runtime_callbacks (void)
551 mono_install_trampoline (MonoTrampoline func)
553 arch_create_jit_trampoline = func? func: default_trampoline;
557 mono_install_jump_trampoline (MonoJumpTrampoline func)
559 arch_create_jump_trampoline = func? func: default_jump_trampoline;
562 #ifndef DISABLE_REMOTING
564 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
566 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
571 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
573 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
577 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
578 imt_thunk_builder = func;
581 static MonoCompileFunc default_mono_compile_method = NULL;
584 * mono_install_compile_method:
585 * @func: function to install
587 * This is a VM internal routine
590 mono_install_compile_method (MonoCompileFunc func)
592 default_mono_compile_method = func;
596 * mono_compile_method:
597 * @method: The method to compile.
599 * This JIT-compiles the method, and returns the pointer to the native code
603 mono_compile_method (MonoMethod *method)
605 MONO_REQ_GC_NEUTRAL_MODE
607 if (!default_mono_compile_method) {
608 g_error ("compile method called on uninitialized runtime");
611 return default_mono_compile_method (method);
615 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
617 MONO_REQ_GC_NEUTRAL_MODE
619 return arch_create_jump_trampoline (domain, method, add_sync_wrapper);
623 mono_runtime_create_delegate_trampoline (MonoClass *klass)
625 MONO_REQ_GC_NEUTRAL_MODE
627 return arch_create_delegate_trampoline (mono_domain_get (), klass);
630 static MonoFreeMethodFunc default_mono_free_method = NULL;
633 * mono_install_free_method:
634 * @func: pointer to the MonoFreeMethodFunc used to release a method
636 * This is an internal VM routine, it is used for the engines to
637 * register a handler to release the resources associated with a method.
639 * Methods are freed when no more references to the delegate that holds
643 mono_install_free_method (MonoFreeMethodFunc func)
645 default_mono_free_method = func;
649 * mono_runtime_free_method:
650 * @domain; domain where the method is hosted
651 * @method: method to release
653 * This routine is invoked to free the resources associated with
654 * a method that has been JIT compiled. This is used to discard
655 * methods that were used only temporarily (for example, used in marshalling)
659 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
661 MONO_REQ_GC_NEUTRAL_MODE
663 if (default_mono_free_method != NULL)
664 default_mono_free_method (domain, method);
666 mono_method_clear_object (domain, method);
668 mono_free_method (method);
672 * The vtables in the root appdomain are assumed to be reachable by other
673 * roots, and we don't use typed allocation in the other domains.
676 /* The sync block is no longer a GC pointer */
677 #define GC_HEADER_BITMAP (0)
679 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
682 compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
684 MONO_REQ_GC_NEUTRAL_MODE;
686 MonoClassField *field;
692 max_size = mono_class_data_size (class) / sizeof (gpointer);
694 max_size = class->instance_size / sizeof (gpointer);
695 if (max_size > size) {
696 g_assert (offset <= 0);
697 bitmap = g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
702 /*An Ephemeron cannot be marked by sgen*/
703 if (!static_fields && class->image == mono_defaults.corlib && !strcmp ("Ephemeron", class->name)) {
705 memset (bitmap, 0, size / 8);
710 for (p = class; p != NULL; p = p->parent) {
711 gpointer iter = NULL;
712 while ((field = mono_class_get_fields (p, &iter))) {
716 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
718 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
721 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
724 /* FIXME: should not happen, flag as type load error */
725 if (field->type->byref)
728 if (static_fields && field->offset == -1)
732 pos = field->offset / sizeof (gpointer);
735 type = mono_type_get_underlying_type (field->type);
736 switch (type->type) {
739 case MONO_TYPE_FNPTR:
741 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
746 if (class->image != mono_defaults.corlib)
749 case MONO_TYPE_STRING:
750 case MONO_TYPE_SZARRAY:
751 case MONO_TYPE_CLASS:
752 case MONO_TYPE_OBJECT:
753 case MONO_TYPE_ARRAY:
754 g_assert ((field->offset % sizeof(gpointer)) == 0);
756 g_assert (pos < size || pos <= max_size);
757 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
758 *max_set = MAX (*max_set, pos);
760 case MONO_TYPE_GENERICINST:
761 if (!mono_type_generic_inst_is_valuetype (type)) {
762 g_assert ((field->offset % sizeof(gpointer)) == 0);
764 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
765 *max_set = MAX (*max_set, pos);
770 case MONO_TYPE_VALUETYPE: {
771 MonoClass *fclass = mono_class_from_mono_type (field->type);
772 if (fclass->has_references) {
773 /* remove the object header */
774 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
788 case MONO_TYPE_BOOLEAN:
792 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
803 * mono_class_compute_bitmap:
805 * Mono internal function to compute a bitmap of reference fields in a class.
808 mono_class_compute_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
810 MONO_REQ_GC_NEUTRAL_MODE;
812 return compute_class_bitmap (class, bitmap, size, offset, max_set, static_fields);
817 * similar to the above, but sets the bits in the bitmap for any non-ref field
818 * and ignores static fields
821 compute_class_non_ref_bitmap (MonoClass *class, gsize *bitmap, int size, int offset)
823 MonoClassField *field;
828 max_size = class->instance_size / sizeof (gpointer);
829 if (max_size >= size) {
830 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
833 for (p = class; p != NULL; p = p->parent) {
834 gpointer iter = NULL;
835 while ((field = mono_class_get_fields (p, &iter))) {
838 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
840 /* FIXME: should not happen, flag as type load error */
841 if (field->type->byref)
844 pos = field->offset / sizeof (gpointer);
847 type = mono_type_get_underlying_type (field->type);
848 switch (type->type) {
849 #if SIZEOF_VOID_P == 8
853 case MONO_TYPE_FNPTR:
858 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
859 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
860 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
863 #if SIZEOF_VOID_P == 4
867 case MONO_TYPE_FNPTR:
872 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
873 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
874 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
880 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
881 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
882 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
885 case MONO_TYPE_BOOLEAN:
888 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
890 case MONO_TYPE_STRING:
891 case MONO_TYPE_SZARRAY:
892 case MONO_TYPE_CLASS:
893 case MONO_TYPE_OBJECT:
894 case MONO_TYPE_ARRAY:
896 case MONO_TYPE_GENERICINST:
897 if (!mono_type_generic_inst_is_valuetype (type)) {
902 case MONO_TYPE_VALUETYPE: {
903 MonoClass *fclass = mono_class_from_mono_type (field->type);
904 /* remove the object header */
905 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
909 g_assert_not_reached ();
918 * mono_class_insecure_overlapping:
919 * check if a class with explicit layout has references and non-references
920 * fields overlapping.
922 * Returns: TRUE if it is insecure to load the type.
925 mono_class_insecure_overlapping (MonoClass *klass)
929 gsize default_bitmap [4] = {0};
931 gsize default_nrbitmap [4] = {0};
932 int i, insecure = FALSE;
935 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
936 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
938 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
939 int idx = i % (sizeof (bitmap [0]) * 8);
940 if (bitmap [idx] & nrbitmap [idx]) {
945 if (bitmap != default_bitmap)
947 if (nrbitmap != default_nrbitmap)
950 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
958 mono_string_alloc (int length)
960 MONO_REQ_GC_UNSAFE_MODE;
961 return mono_string_new_size (mono_domain_get (), length);
965 mono_class_compute_gc_descriptor (MonoClass *class)
967 MONO_REQ_GC_NEUTRAL_MODE;
971 gsize default_bitmap [4] = {0};
972 static gboolean gcj_inited = FALSE;
977 mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
978 mono_register_jit_icall (mono_string_alloc, "mono_string_alloc", mono_create_icall_signature ("object int"), FALSE);
981 mono_loader_unlock ();
985 mono_class_init (class);
987 if (class->gc_descr_inited)
990 class->gc_descr_inited = TRUE;
991 class->gc_descr = MONO_GC_DESCRIPTOR_NULL;
993 bitmap = default_bitmap;
994 if (class == mono_defaults.string_class) {
995 class->gc_descr = mono_gc_make_descr_for_string (bitmap, 2);
996 } else if (class->rank) {
997 mono_class_compute_gc_descriptor (class->element_class);
998 if (MONO_TYPE_IS_REFERENCE (&class->element_class->byval_arg)) {
1000 class->gc_descr = mono_gc_make_descr_for_array (class->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
1001 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1002 class->name_space, class->name);*/
1004 /* remove the object header */
1005 bitmap = compute_class_bitmap (class->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
1006 class->gc_descr = mono_gc_make_descr_for_array (class->byval_arg.type == MONO_TYPE_SZARRAY, bitmap, mono_array_element_size (class) / sizeof (gpointer), mono_array_element_size (class));
1007 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1008 class->name_space, class->name);*/
1009 if (bitmap != default_bitmap)
1013 /*static int count = 0;
1016 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1017 class->gc_descr = mono_gc_make_descr_for_object (bitmap, max_set + 1, class->instance_size);
1019 if (class->gc_descr == MONO_GC_DESCRIPTOR_NULL)
1020 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
1022 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
1023 if (bitmap != default_bitmap)
1029 * field_is_special_static:
1030 * @fklass: The MonoClass to look up.
1031 * @field: The MonoClassField describing the field.
1033 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1034 * SPECIAL_STATIC_NONE otherwise.
1037 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1039 MONO_REQ_GC_NEUTRAL_MODE;
1041 MonoCustomAttrInfo *ainfo;
1043 ainfo = mono_custom_attrs_from_field (fklass, field);
1046 for (i = 0; i < ainfo->num_attrs; ++i) {
1047 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1048 if (klass->image == mono_defaults.corlib) {
1049 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1050 mono_custom_attrs_free (ainfo);
1051 return SPECIAL_STATIC_THREAD;
1053 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1054 mono_custom_attrs_free (ainfo);
1055 return SPECIAL_STATIC_CONTEXT;
1059 mono_custom_attrs_free (ainfo);
1060 return SPECIAL_STATIC_NONE;
1063 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1064 #define mix(a,b,c) { \
1065 a -= c; a ^= rot(c, 4); c += b; \
1066 b -= a; b ^= rot(a, 6); a += c; \
1067 c -= b; c ^= rot(b, 8); b += a; \
1068 a -= c; a ^= rot(c,16); c += b; \
1069 b -= a; b ^= rot(a,19); a += c; \
1070 c -= b; c ^= rot(b, 4); b += a; \
1072 #define final(a,b,c) { \
1073 c ^= b; c -= rot(b,14); \
1074 a ^= c; a -= rot(c,11); \
1075 b ^= a; b -= rot(a,25); \
1076 c ^= b; c -= rot(b,16); \
1077 a ^= c; a -= rot(c,4); \
1078 b ^= a; b -= rot(a,14); \
1079 c ^= b; c -= rot(b,24); \
1083 * mono_method_get_imt_slot:
1085 * The IMT slot is embedded into AOTed code, so this must return the same value
1086 * for the same method across all executions. This means:
1087 * - pointers shouldn't be used as hash values.
1088 * - mono_metadata_str_hash () should be used for hashing strings.
1091 mono_method_get_imt_slot (MonoMethod *method)
1093 MONO_REQ_GC_NEUTRAL_MODE;
1095 MonoMethodSignature *sig;
1097 guint32 *hashes_start, *hashes;
1101 /* This can be used to stress tests the collision code */
1105 * We do this to simplify generic sharing. It will hurt
1106 * performance in cases where a class implements two different
1107 * instantiations of the same generic interface.
1108 * The code in build_imt_slots () depends on this.
1110 if (method->is_inflated)
1111 method = ((MonoMethodInflated*)method)->declaring;
1113 sig = mono_method_signature (method);
1114 hashes_count = sig->param_count + 4;
1115 hashes_start = malloc (hashes_count * sizeof (guint32));
1116 hashes = hashes_start;
1118 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1119 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1120 method->klass->name_space, method->klass->name, method->name);
1123 /* Initialize hashes */
1124 hashes [0] = mono_metadata_str_hash (method->klass->name);
1125 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1126 hashes [2] = mono_metadata_str_hash (method->name);
1127 hashes [3] = mono_metadata_type_hash (sig->ret);
1128 for (i = 0; i < sig->param_count; i++) {
1129 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1132 /* Setup internal state */
1133 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1135 /* Handle most of the hashes */
1136 while (hashes_count > 3) {
1145 /* Handle the last 3 hashes (all the case statements fall through) */
1146 switch (hashes_count) {
1147 case 3 : c += hashes [2];
1148 case 2 : b += hashes [1];
1149 case 1 : a += hashes [0];
1151 case 0: /* nothing left to add */
1155 free (hashes_start);
1156 /* Report the result */
1157 return c % MONO_IMT_SIZE;
1166 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1167 MONO_REQ_GC_NEUTRAL_MODE;
1169 guint32 imt_slot = mono_method_get_imt_slot (method);
1170 MonoImtBuilderEntry *entry;
1172 if (slot_num >= 0 && imt_slot != slot_num) {
1173 /* we build just a single imt slot and this is not it */
1177 entry = g_malloc0 (sizeof (MonoImtBuilderEntry));
1178 entry->key = method;
1179 entry->value.vtable_slot = vtable_slot;
1180 entry->next = imt_builder [imt_slot];
1181 if (imt_builder [imt_slot] != NULL) {
1182 entry->children = imt_builder [imt_slot]->children + 1;
1183 if (entry->children == 1) {
1184 mono_stats.imt_slots_with_collisions++;
1185 *imt_collisions_bitmap |= (1 << imt_slot);
1188 entry->children = 0;
1189 mono_stats.imt_used_slots++;
1191 imt_builder [imt_slot] = entry;
1194 char *method_name = mono_method_full_name (method, TRUE);
1195 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1196 method, method_name, imt_slot, vtable_slot, entry->children);
1197 g_free (method_name);
1204 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1206 MonoMethod *method = e->key;
1207 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1211 method->klass->name_space,
1212 method->klass->name,
1215 printf (" * %s: NULL\n", message);
1221 compare_imt_builder_entries (const void *p1, const void *p2) {
1222 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1223 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1225 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1229 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1231 MONO_REQ_GC_NEUTRAL_MODE;
1233 int count = end - start;
1234 int chunk_start = out_array->len;
1237 for (i = start; i < end; ++i) {
1238 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1239 item->key = sorted_array [i]->key;
1240 item->value = sorted_array [i]->value;
1241 item->has_target_code = sorted_array [i]->has_target_code;
1242 item->is_equals = TRUE;
1244 item->check_target_idx = out_array->len + 1;
1246 item->check_target_idx = 0;
1247 g_ptr_array_add (out_array, item);
1250 int middle = start + count / 2;
1251 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1253 item->key = sorted_array [middle]->key;
1254 item->is_equals = FALSE;
1255 g_ptr_array_add (out_array, item);
1256 imt_emit_ir (sorted_array, start, middle, out_array);
1257 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1263 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1264 MONO_REQ_GC_NEUTRAL_MODE;
1266 int number_of_entries = entries->children + 1;
1267 MonoImtBuilderEntry **sorted_array = malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1268 GPtrArray *result = g_ptr_array_new ();
1269 MonoImtBuilderEntry *current_entry;
1272 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1273 sorted_array [i] = current_entry;
1275 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1277 /*for (i = 0; i < number_of_entries; i++) {
1278 print_imt_entry (" sorted array:", sorted_array [i], i);
1281 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1283 free (sorted_array);
1288 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1290 MONO_REQ_GC_NEUTRAL_MODE;
1292 if (imt_builder_entry != NULL) {
1293 if (imt_builder_entry->children == 0 && !fail_tramp) {
1294 /* No collision, return the vtable slot contents */
1295 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1297 /* Collision, build the thunk */
1298 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1301 result = imt_thunk_builder (vtable, domain,
1302 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1303 for (i = 0; i < imt_ir->len; ++i)
1304 g_free (g_ptr_array_index (imt_ir, i));
1305 g_ptr_array_free (imt_ir, TRUE);
1317 static MonoImtBuilderEntry*
1318 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1321 * LOCKING: requires the loader and domain locks.
1325 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1327 MONO_REQ_GC_NEUTRAL_MODE;
1331 guint32 imt_collisions_bitmap = 0;
1332 MonoImtBuilderEntry **imt_builder = calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1333 int method_count = 0;
1334 gboolean record_method_count_for_max_collisions = FALSE;
1335 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1338 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1340 for (i = 0; i < klass->interface_offsets_count; ++i) {
1341 MonoClass *iface = klass->interfaces_packed [i];
1342 int interface_offset = klass->interface_offsets_packed [i];
1343 int method_slot_in_interface, vt_slot;
1345 if (mono_class_has_variant_generic_params (iface))
1346 has_variant_iface = TRUE;
1348 mono_class_setup_methods (iface);
1349 vt_slot = interface_offset;
1350 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1353 if (slot_num >= 0 && iface->is_inflated) {
1355 * The imt slot of the method is the same as for its declaring method,
1356 * see the comment in mono_method_get_imt_slot (), so we can
1357 * avoid inflating methods which will be discarded by
1358 * add_imt_builder_entry anyway.
1360 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1361 if (mono_method_get_imt_slot (method) != slot_num) {
1366 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1367 if (method->is_generic) {
1368 has_generic_virtual = TRUE;
1373 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1374 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1379 if (extra_interfaces) {
1380 int interface_offset = klass->vtable_size;
1382 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1383 MonoClass* iface = list_item->data;
1384 int method_slot_in_interface;
1385 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1386 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1388 if (method->is_generic)
1389 has_generic_virtual = TRUE;
1390 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1392 interface_offset += iface->method.count;
1395 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1396 /* overwrite the imt slot only if we're building all the entries or if
1397 * we're building this specific one
1399 if (slot_num < 0 || i == slot_num) {
1400 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1403 if (imt_builder [i]) {
1404 MonoImtBuilderEntry *entry;
1406 /* Link entries with imt_builder [i] */
1407 for (entry = entries; entry->next; entry = entry->next) {
1409 MonoMethod *method = (MonoMethod*)entry->key;
1410 char *method_name = mono_method_full_name (method, TRUE);
1411 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1412 g_free (method_name);
1415 entry->next = imt_builder [i];
1416 entries->children += imt_builder [i]->children + 1;
1418 imt_builder [i] = entries;
1421 if (has_generic_virtual || has_variant_iface) {
1423 * There might be collisions later when the the thunk is expanded.
1425 imt_collisions_bitmap |= (1 << i);
1428 * The IMT thunk might be called with an instance of one of the
1429 * generic virtual methods, so has to fallback to the IMT trampoline.
1431 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline (i));
1433 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1436 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1440 if (imt_builder [i] != NULL) {
1441 int methods_in_slot = imt_builder [i]->children + 1;
1442 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1443 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1444 record_method_count_for_max_collisions = TRUE;
1446 method_count += methods_in_slot;
1450 mono_stats.imt_number_of_methods += method_count;
1451 if (record_method_count_for_max_collisions) {
1452 mono_stats.imt_method_count_when_max_collisions = method_count;
1455 for (i = 0; i < MONO_IMT_SIZE; i++) {
1456 MonoImtBuilderEntry* entry = imt_builder [i];
1457 while (entry != NULL) {
1458 MonoImtBuilderEntry* next = entry->next;
1464 /* we OR the bitmap since we may build just a single imt slot at a time */
1465 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1469 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1470 MONO_REQ_GC_NEUTRAL_MODE;
1472 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1476 * mono_vtable_build_imt_slot:
1477 * @vtable: virtual object table struct
1478 * @imt_slot: slot in the IMT table
1480 * Fill the given @imt_slot in the IMT table of @vtable with
1481 * a trampoline or a thunk for the case of collisions.
1482 * This is part of the internal mono API.
1484 * LOCKING: Take the domain lock.
1487 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1489 MONO_REQ_GC_NEUTRAL_MODE;
1491 gpointer *imt = (gpointer*)vtable;
1492 imt -= MONO_IMT_SIZE;
1493 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1495 /* no support for extra interfaces: the proxy objects will need
1496 * to build the complete IMT
1497 * Update and heck needs to ahppen inside the proper domain lock, as all
1498 * the changes made to a MonoVTable.
1500 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1501 mono_domain_lock (vtable->domain);
1502 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1503 if (imt [imt_slot] == callbacks.get_imt_trampoline (imt_slot))
1504 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1505 mono_domain_unlock (vtable->domain);
1506 mono_loader_unlock ();
1511 * The first two free list entries both belong to the wait list: The
1512 * first entry is the pointer to the head of the list and the second
1513 * entry points to the last element. That way appending and removing
1514 * the first element are both O(1) operations.
1516 #ifdef MONO_SMALL_CONFIG
1517 #define NUM_FREE_LISTS 6
1519 #define NUM_FREE_LISTS 12
1521 #define FIRST_FREE_LIST_SIZE 64
1522 #define MAX_WAIT_LENGTH 50
1523 #define THUNK_THRESHOLD 10
1526 * LOCKING: The domain lock must be held.
1529 init_thunk_free_lists (MonoDomain *domain)
1531 MONO_REQ_GC_NEUTRAL_MODE;
1533 if (domain->thunk_free_lists)
1535 domain->thunk_free_lists = mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1539 list_index_for_size (int item_size)
1542 int size = FIRST_FREE_LIST_SIZE;
1544 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1553 * mono_method_alloc_generic_virtual_thunk:
1555 * @size: size in bytes
1557 * Allocs size bytes to be used for the code of a generic virtual
1558 * thunk. It's either allocated from the domain's code manager or
1559 * reused from a previously invalidated piece.
1561 * LOCKING: The domain lock must be held.
1564 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1566 MONO_REQ_GC_NEUTRAL_MODE;
1568 static gboolean inited = FALSE;
1569 static int generic_virtual_thunks_size = 0;
1573 MonoThunkFreeList **l;
1575 init_thunk_free_lists (domain);
1577 size += sizeof (guint32);
1578 if (size < sizeof (MonoThunkFreeList))
1579 size = sizeof (MonoThunkFreeList);
1581 i = list_index_for_size (size);
1582 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1583 if ((*l)->size >= size) {
1584 MonoThunkFreeList *item = *l;
1586 return ((guint32*)item) + 1;
1590 /* no suitable item found - search lists of larger sizes */
1591 while (++i < NUM_FREE_LISTS) {
1592 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1595 g_assert (item->size > size);
1596 domain->thunk_free_lists [i] = item->next;
1597 return ((guint32*)item) + 1;
1600 /* still nothing found - allocate it */
1602 mono_counters_register ("Generic virtual thunk bytes",
1603 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1606 generic_virtual_thunks_size += size;
1608 p = mono_domain_code_reserve (domain, size);
1611 mono_domain_lock (domain);
1612 if (!domain->generic_virtual_thunks)
1613 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1614 g_hash_table_insert (domain->generic_virtual_thunks, p, p);
1615 mono_domain_unlock (domain);
1621 * LOCKING: The domain lock must be held.
1624 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1626 MONO_REQ_GC_NEUTRAL_MODE;
1629 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1630 gboolean found = FALSE;
1632 mono_domain_lock (domain);
1633 if (!domain->generic_virtual_thunks)
1634 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1635 if (g_hash_table_lookup (domain->generic_virtual_thunks, l))
1637 mono_domain_unlock (domain);
1640 /* Not allocated by mono_method_alloc_generic_virtual_thunk (), i.e. AOT */
1642 init_thunk_free_lists (domain);
1644 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1645 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1646 int length = item->length;
1649 /* unlink the first item from the wait list */
1650 domain->thunk_free_lists [0] = item->next;
1651 domain->thunk_free_lists [0]->length = length - 1;
1653 i = list_index_for_size (item->size);
1655 /* put it in the free list */
1656 item->next = domain->thunk_free_lists [i];
1657 domain->thunk_free_lists [i] = item;
1661 if (domain->thunk_free_lists [1]) {
1662 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1663 domain->thunk_free_lists [0]->length++;
1665 g_assert (!domain->thunk_free_lists [0]);
1667 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1668 domain->thunk_free_lists [0]->length = 1;
1672 typedef struct _GenericVirtualCase {
1676 struct _GenericVirtualCase *next;
1677 } GenericVirtualCase;
1680 * get_generic_virtual_entries:
1682 * Return IMT entries for the generic virtual method instances and
1683 * variant interface methods for vtable slot
1686 static MonoImtBuilderEntry*
1687 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1689 MONO_REQ_GC_NEUTRAL_MODE;
1691 GenericVirtualCase *list;
1692 MonoImtBuilderEntry *entries;
1694 mono_domain_lock (domain);
1695 if (!domain->generic_virtual_cases)
1696 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1698 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1701 for (; list; list = list->next) {
1702 MonoImtBuilderEntry *entry;
1704 if (list->count < THUNK_THRESHOLD)
1707 entry = g_new0 (MonoImtBuilderEntry, 1);
1708 entry->key = list->method;
1709 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1710 entry->has_target_code = 1;
1712 entry->children = entries->children + 1;
1713 entry->next = entries;
1717 mono_domain_unlock (domain);
1719 /* FIXME: Leaking memory ? */
1724 * mono_method_add_generic_virtual_invocation:
1726 * @vtable_slot: pointer to the vtable slot
1727 * @method: the inflated generic virtual method
1728 * @code: the method's code
1730 * Registers a call via unmanaged code to a generic virtual method
1731 * instantiation or variant interface method. If the number of calls reaches a threshold
1732 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1733 * virtual method thunk.
1736 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1737 gpointer *vtable_slot,
1738 MonoMethod *method, gpointer code)
1740 MONO_REQ_GC_NEUTRAL_MODE;
1742 static gboolean inited = FALSE;
1743 static int num_added = 0;
1745 GenericVirtualCase *gvc, *list;
1746 MonoImtBuilderEntry *entries;
1750 mono_domain_lock (domain);
1751 if (!domain->generic_virtual_cases)
1752 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1754 /* Check whether the case was already added */
1755 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1758 if (gvc->method == method)
1763 /* If not found, make a new one */
1765 gvc = mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1766 gvc->method = method;
1769 gvc->next = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1771 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1774 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1780 if (++gvc->count == THUNK_THRESHOLD) {
1781 gpointer *old_thunk = *vtable_slot;
1782 gpointer vtable_trampoline = NULL;
1783 gpointer imt_trampoline = NULL;
1785 if ((gpointer)vtable_slot < (gpointer)vtable) {
1786 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1787 int imt_slot = MONO_IMT_SIZE + displacement;
1789 /* Force the rebuild of the thunk at the next call */
1790 imt_trampoline = callbacks.get_imt_trampoline (imt_slot);
1791 *vtable_slot = imt_trampoline;
1793 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline ((gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1795 entries = get_generic_virtual_entries (domain, vtable_slot);
1797 sorted = imt_sort_slot_entries (entries);
1799 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1803 MonoImtBuilderEntry *next = entries->next;
1808 for (i = 0; i < sorted->len; ++i)
1809 g_free (g_ptr_array_index (sorted, i));
1810 g_ptr_array_free (sorted, TRUE);
1813 #ifndef __native_client__
1814 /* We don't re-use any thunks as there is a lot of overhead */
1815 /* to deleting and re-using code in Native Client. */
1816 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1817 invalidate_generic_virtual_thunk (domain, old_thunk);
1821 mono_domain_unlock (domain);
1824 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error);
1827 * mono_class_vtable:
1828 * @domain: the application domain
1829 * @class: the class to initialize
1831 * VTables are domain specific because we create domain specific code, and
1832 * they contain the domain specific static class data.
1833 * On failure, NULL is returned, and class->exception_type is set.
1836 mono_class_vtable (MonoDomain *domain, MonoClass *class)
1838 return mono_class_vtable_full (domain, class, FALSE);
1842 * mono_class_vtable_full:
1843 * @domain: the application domain
1844 * @class: the class to initialize
1845 * @raise_on_error if an exception should be raised on failure or not
1847 * VTables are domain specific because we create domain specific code, and
1848 * they contain the domain specific static class data.
1851 mono_class_vtable_full (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1853 MONO_REQ_GC_UNSAFE_MODE;
1855 MonoClassRuntimeInfo *runtime_info;
1859 if (class->exception_type) {
1861 mono_raise_exception (mono_class_get_exception_for_failure (class));
1865 /* this check can be inlined in jitted code, too */
1866 runtime_info = class->runtime_info;
1867 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1868 return runtime_info->domain_vtables [domain->domain_id];
1869 return mono_class_create_runtime_vtable (domain, class, raise_on_error);
1873 * mono_class_try_get_vtable:
1874 * @domain: the application domain
1875 * @class: the class to initialize
1877 * This function tries to get the associated vtable from @class if
1878 * it was already created.
1881 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *class)
1883 MONO_REQ_GC_NEUTRAL_MODE;
1885 MonoClassRuntimeInfo *runtime_info;
1889 runtime_info = class->runtime_info;
1890 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1891 return runtime_info->domain_vtables [domain->domain_id];
1896 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1898 MONO_REQ_GC_NEUTRAL_MODE;
1900 size_t alloc_offset;
1903 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1904 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1905 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1907 if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1908 g_assert ((imt_table_bytes & 7) == 4);
1915 return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1919 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1921 MONO_REQ_GC_UNSAFE_MODE;
1924 MonoClassRuntimeInfo *runtime_info, *old_info;
1925 MonoClassField *field;
1927 int i, vtable_slots;
1928 size_t imt_table_bytes;
1930 guint32 vtable_size, class_size;
1932 gpointer *interface_offsets;
1934 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1935 mono_domain_lock (domain);
1936 runtime_info = class->runtime_info;
1937 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1938 mono_domain_unlock (domain);
1939 mono_loader_unlock ();
1940 return runtime_info->domain_vtables [domain->domain_id];
1942 if (!class->inited || class->exception_type) {
1943 if (!mono_class_init (class) || class->exception_type) {
1944 mono_domain_unlock (domain);
1945 mono_loader_unlock ();
1947 mono_raise_exception (mono_class_get_exception_for_failure (class));
1952 /* Array types require that their element type be valid*/
1953 if (class->byval_arg.type == MONO_TYPE_ARRAY || class->byval_arg.type == MONO_TYPE_SZARRAY) {
1954 MonoClass *element_class = class->element_class;
1955 if (!element_class->inited)
1956 mono_class_init (element_class);
1958 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1959 if (element_class->exception_type == MONO_EXCEPTION_NONE && !element_class->vtable_size)
1960 mono_class_setup_vtable (element_class);
1962 if (element_class->exception_type != MONO_EXCEPTION_NONE) {
1963 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1964 if (class->exception_type == MONO_EXCEPTION_NONE)
1965 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
1966 mono_domain_unlock (domain);
1967 mono_loader_unlock ();
1969 mono_raise_exception (mono_class_get_exception_for_failure (class));
1975 * For some classes, mono_class_init () already computed class->vtable_size, and
1976 * that is all that is needed because of the vtable trampolines.
1978 if (!class->vtable_size)
1979 mono_class_setup_vtable (class);
1981 if (class->generic_class && !class->vtable)
1982 mono_class_check_vtable_constraints (class, NULL);
1984 /* Initialize klass->has_finalize */
1985 mono_class_has_finalizer (class);
1987 if (class->exception_type) {
1988 mono_domain_unlock (domain);
1989 mono_loader_unlock ();
1991 mono_raise_exception (mono_class_get_exception_for_failure (class));
1995 vtable_slots = class->vtable_size;
1996 /* we add an additional vtable slot to store the pointer to static field data only when needed */
1997 class_size = mono_class_data_size (class);
2001 if (class->interface_offsets_count) {
2002 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
2003 mono_stats.imt_number_of_tables++;
2004 mono_stats.imt_tables_size += imt_table_bytes;
2006 imt_table_bytes = 0;
2009 vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
2011 mono_stats.used_class_count++;
2012 mono_stats.class_vtable_size += vtable_size;
2014 interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
2015 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2016 g_assert (!((gsize)vt & 7));
2019 vt->rank = class->rank;
2020 vt->domain = domain;
2022 mono_class_compute_gc_descriptor (class);
2024 * We can't use typed allocation in the non-root domains, since the
2025 * collector needs the GC descriptor stored in the vtable even after
2026 * the mempool containing the vtable is destroyed when the domain is
2027 * unloaded. An alternative might be to allocate vtables in the GC
2028 * heap, but this does not seem to work (it leads to crashes inside
2029 * libgc). If that approach is tried, two gc descriptors need to be
2030 * allocated for each class: one for the root domain, and one for all
2031 * other domains. The second descriptor should contain a bit for the
2032 * vtable field in MonoObject, since we can no longer assume the
2033 * vtable is reachable by other roots after the appdomain is unloaded.
2035 #ifdef HAVE_BOEHM_GC
2036 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
2037 vt->gc_descr = MONO_GC_DESCRIPTOR_NULL;
2040 vt->gc_descr = class->gc_descr;
2042 gc_bits = mono_gc_get_vtable_bits (class);
2043 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
2045 vt->gc_bits = gc_bits;
2048 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
2049 if (class->has_static_refs) {
2050 MonoGCDescriptor statics_gc_descr;
2052 gsize default_bitmap [4] = {0};
2055 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
2056 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
2057 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
2058 vt->vtable [class->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr, MONO_ROOT_SOURCE_STATIC, "managed static variables");
2059 mono_domain_add_class_static_data (domain, class, vt->vtable [class->vtable_size], NULL);
2060 if (bitmap != default_bitmap)
2063 vt->vtable [class->vtable_size] = mono_domain_alloc0 (domain, class_size);
2065 vt->has_static_fields = TRUE;
2066 mono_stats.class_static_data_size += class_size;
2070 while ((field = mono_class_get_fields (class, &iter))) {
2071 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2073 if (mono_field_is_deleted (field))
2075 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2076 gint32 special_static = class->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (class, field);
2077 if (special_static != SPECIAL_STATIC_NONE) {
2078 guint32 size, offset;
2080 gsize default_bitmap [4] = {0};
2085 if (mono_type_is_reference (field->type)) {
2086 default_bitmap [0] = 1;
2088 bitmap = default_bitmap;
2089 } else if (mono_type_is_struct (field->type)) {
2090 fclass = mono_class_from_mono_type (field->type);
2091 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
2092 numbits = max_set + 1;
2094 default_bitmap [0] = 0;
2096 bitmap = default_bitmap;
2098 size = mono_type_size (field->type, &align);
2099 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
2100 if (!domain->special_static_fields)
2101 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2102 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2103 if (bitmap != default_bitmap)
2106 * This marks the field as special static to speed up the
2107 * checks in mono_field_static_get/set_value ().
2113 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2114 MonoClass *fklass = mono_class_from_mono_type (field->type);
2115 const char *data = mono_field_get_data (field);
2117 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2118 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2119 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2122 if (fklass->valuetype) {
2123 memcpy (t, data, mono_class_value_size (fklass, NULL));
2125 /* it's a pointer type: add check */
2126 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2133 vt->max_interface_id = class->max_interface_id;
2134 vt->interface_bitmap = class->interface_bitmap;
2136 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2137 // class->name, class->interface_offsets_count);
2139 /* Initialize vtable */
2140 if (callbacks.get_vtable_trampoline) {
2141 // This also covers the AOT case
2142 for (i = 0; i < class->vtable_size; ++i) {
2143 vt->vtable [i] = callbacks.get_vtable_trampoline (i);
2146 mono_class_setup_vtable (class);
2148 for (i = 0; i < class->vtable_size; ++i) {
2151 if ((cm = class->vtable [i]))
2152 vt->vtable [i] = arch_create_jit_trampoline (cm);
2156 if (imt_table_bytes) {
2157 /* Now that the vtable is full, we can actually fill up the IMT */
2158 for (i = 0; i < MONO_IMT_SIZE; ++i)
2159 interface_offsets [i] = callbacks.get_imt_trampoline (i);
2163 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2164 * re-acquire them and check if another thread has created the vtable in the meantime.
2166 /* Special case System.MonoType to avoid infinite recursion */
2167 if (class != mono_defaults.monotype_class) {
2168 /*FIXME check for OOM*/
2169 vt->type = mono_type_get_object (domain, &class->byval_arg);
2170 if (mono_object_get_class (vt->type) != mono_defaults.monotype_class)
2171 /* This is unregistered in
2172 unregister_vtable_reflection_type() in
2174 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2177 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (class));
2179 /* class_vtable_array keeps an array of created vtables
2181 g_ptr_array_add (domain->class_vtable_array, vt);
2182 /* class->runtime_info is protected by the loader lock, both when
2183 * it it enlarged and when it is stored info.
2187 * Store the vtable in class->runtime_info.
2188 * class->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2190 mono_memory_barrier ();
2192 old_info = class->runtime_info;
2193 if (old_info && old_info->max_domain >= domain->domain_id) {
2194 /* someone already created a large enough runtime info */
2195 old_info->domain_vtables [domain->domain_id] = vt;
2197 int new_size = domain->domain_id;
2199 new_size = MAX (new_size, old_info->max_domain);
2201 /* make the new size a power of two */
2203 while (new_size > i)
2206 /* this is a bounded memory retention issue: may want to
2207 * handle it differently when we'll have a rcu-like system.
2209 runtime_info = mono_image_alloc0 (class->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2210 runtime_info->max_domain = new_size - 1;
2211 /* copy the stuff from the older info */
2213 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2215 runtime_info->domain_vtables [domain->domain_id] = vt;
2217 mono_memory_barrier ();
2218 class->runtime_info = runtime_info;
2221 if (class == mono_defaults.monotype_class) {
2222 /*FIXME check for OOM*/
2223 vt->type = mono_type_get_object (domain, &class->byval_arg);
2224 if (mono_object_get_class (vt->type) != mono_defaults.monotype_class)
2225 /* This is unregistered in
2226 unregister_vtable_reflection_type() in
2228 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2231 mono_domain_unlock (domain);
2232 mono_loader_unlock ();
2234 /* make sure the parent is initialized */
2235 /*FIXME shouldn't this fail the current type?*/
2237 mono_class_vtable_full (domain, class->parent, raise_on_error);
2242 #ifndef DISABLE_REMOTING
2244 * mono_class_proxy_vtable:
2245 * @domain: the application domain
2246 * @remove_class: the remote class
2248 * Creates a vtable for transparent proxies. It is basically
2249 * a copy of the real vtable of the class wrapped in @remote_class,
2250 * but all function pointers invoke the remoting functions, and
2251 * vtable->klass points to the transparent proxy class, and not to @class.
2254 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2256 MONO_REQ_GC_UNSAFE_MODE;
2259 MonoVTable *vt, *pvt;
2260 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2262 GSList *extra_interfaces = NULL;
2263 MonoClass *class = remote_class->proxy_class;
2264 gpointer *interface_offsets;
2267 size_t imt_table_bytes;
2269 #ifdef COMPRESSED_INTERFACE_BITMAP
2273 vt = mono_class_vtable (domain, class);
2274 g_assert (vt); /*FIXME property handle failure*/
2275 max_interface_id = vt->max_interface_id;
2277 /* Calculate vtable space for extra interfaces */
2278 for (j = 0; j < remote_class->interface_count; j++) {
2279 MonoClass* iclass = remote_class->interfaces[j];
2283 /*FIXME test for interfaces with variant generic arguments*/
2284 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
2285 continue; /* interface implemented by the class */
2286 if (g_slist_find (extra_interfaces, iclass))
2289 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2291 method_count = mono_class_num_methods (iclass);
2293 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2294 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2296 for (i = 0; i < ifaces->len; ++i) {
2297 MonoClass *ic = g_ptr_array_index (ifaces, i);
2298 /*FIXME test for interfaces with variant generic arguments*/
2299 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
2300 continue; /* interface implemented by the class */
2301 if (g_slist_find (extra_interfaces, ic))
2303 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2304 method_count += mono_class_num_methods (ic);
2306 g_ptr_array_free (ifaces, TRUE);
2309 extra_interface_vtsize += method_count * sizeof (gpointer);
2310 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2313 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2314 mono_stats.imt_number_of_tables++;
2315 mono_stats.imt_tables_size += imt_table_bytes;
2317 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2319 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2321 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2322 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2323 g_assert (!((gsize)pvt & 7));
2325 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer));
2327 pvt->klass = mono_defaults.transparent_proxy_class;
2328 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2329 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2331 /* initialize vtable */
2332 mono_class_setup_vtable (class);
2333 for (i = 0; i < class->vtable_size; ++i) {
2336 if ((cm = class->vtable [i]))
2337 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2339 pvt->vtable [i] = NULL;
2342 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2343 /* create trampolines for abstract methods */
2344 for (k = class; k; k = k->parent) {
2346 gpointer iter = NULL;
2347 while ((m = mono_class_get_methods (k, &iter)))
2348 if (!pvt->vtable [m->slot])
2349 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2353 pvt->max_interface_id = max_interface_id;
2354 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2355 #ifdef COMPRESSED_INTERFACE_BITMAP
2356 bitmap = g_malloc0 (bsize);
2358 bitmap = mono_domain_alloc0 (domain, bsize);
2361 for (i = 0; i < class->interface_offsets_count; ++i) {
2362 int interface_id = class->interfaces_packed [i]->interface_id;
2363 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2366 if (extra_interfaces) {
2367 int slot = class->vtable_size;
2373 /* Create trampolines for the methods of the interfaces */
2374 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2375 interf = list_item->data;
2377 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2381 while ((cm = mono_class_get_methods (interf, &iter)))
2382 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2384 slot += mono_class_num_methods (interf);
2388 /* Now that the vtable is full, we can actually fill up the IMT */
2389 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
2390 if (extra_interfaces) {
2391 g_slist_free (extra_interfaces);
2394 #ifdef COMPRESSED_INTERFACE_BITMAP
2395 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2396 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2397 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2400 pvt->interface_bitmap = bitmap;
2405 #endif /* DISABLE_REMOTING */
2408 * mono_class_field_is_special_static:
2410 * Returns whether @field is a thread/context static field.
2413 mono_class_field_is_special_static (MonoClassField *field)
2415 MONO_REQ_GC_NEUTRAL_MODE
2417 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2419 if (mono_field_is_deleted (field))
2421 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2422 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2429 * mono_class_field_get_special_static_type:
2430 * @field: The MonoClassField describing the field.
2432 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2433 * SPECIAL_STATIC_NONE otherwise.
2436 mono_class_field_get_special_static_type (MonoClassField *field)
2438 MONO_REQ_GC_NEUTRAL_MODE
2440 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2441 return SPECIAL_STATIC_NONE;
2442 if (mono_field_is_deleted (field))
2443 return SPECIAL_STATIC_NONE;
2444 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2445 return field_is_special_static (field->parent, field);
2446 return SPECIAL_STATIC_NONE;
2450 * mono_class_has_special_static_fields:
2452 * Returns whenever @klass has any thread/context static fields.
2455 mono_class_has_special_static_fields (MonoClass *klass)
2457 MONO_REQ_GC_NEUTRAL_MODE
2459 MonoClassField *field;
2463 while ((field = mono_class_get_fields (klass, &iter))) {
2464 g_assert (field->parent == klass);
2465 if (mono_class_field_is_special_static (field))
2472 #ifndef DISABLE_REMOTING
2474 * create_remote_class_key:
2475 * Creates an array of pointers that can be used as a hash key for a remote class.
2476 * The first element of the array is the number of pointers.
2479 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2481 MONO_REQ_GC_NEUTRAL_MODE;
2486 if (remote_class == NULL) {
2487 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2488 key = g_malloc (sizeof(gpointer) * 3);
2489 key [0] = GINT_TO_POINTER (2);
2490 key [1] = mono_defaults.marshalbyrefobject_class;
2491 key [2] = extra_class;
2493 key = g_malloc (sizeof(gpointer) * 2);
2494 key [0] = GINT_TO_POINTER (1);
2495 key [1] = extra_class;
2498 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2499 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2500 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2501 key [1] = remote_class->proxy_class;
2503 // Keep the list of interfaces sorted
2504 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2505 if (extra_class && remote_class->interfaces [i] > extra_class) {
2506 key [j++] = extra_class;
2509 key [j] = remote_class->interfaces [i];
2512 key [j] = extra_class;
2514 // Replace the old class. The interface list is the same
2515 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2516 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2517 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2518 for (i = 0; i < remote_class->interface_count; i++)
2519 key [2 + i] = remote_class->interfaces [i];
2527 * copy_remote_class_key:
2529 * Make a copy of KEY in the domain and return the copy.
2532 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2534 MONO_REQ_GC_NEUTRAL_MODE
2536 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2537 gpointer *mp_key = mono_domain_alloc (domain, key_size);
2539 memcpy (mp_key, key, key_size);
2545 * mono_remote_class:
2546 * @domain: the application domain
2547 * @class_name: name of the remote class
2549 * Creates and initializes a MonoRemoteClass object for a remote type.
2551 * Can raise an exception on failure.
2554 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2556 MONO_REQ_GC_UNSAFE_MODE;
2559 MonoRemoteClass *rc;
2560 gpointer* key, *mp_key;
2563 key = create_remote_class_key (NULL, proxy_class);
2565 mono_domain_lock (domain);
2566 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2570 mono_domain_unlock (domain);
2574 name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
2575 if (!mono_error_ok (&error)) {
2577 mono_domain_unlock (domain);
2578 mono_error_raise_exception (&error);
2581 mp_key = copy_remote_class_key (domain, key);
2585 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2586 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2587 rc->interface_count = 1;
2588 rc->interfaces [0] = proxy_class;
2589 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2591 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2592 rc->interface_count = 0;
2593 rc->proxy_class = proxy_class;
2596 rc->default_vtable = NULL;
2597 rc->xdomain_vtable = NULL;
2598 rc->proxy_class_name = name;
2599 #ifndef DISABLE_PERFCOUNTERS
2600 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2603 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2605 mono_domain_unlock (domain);
2610 * clone_remote_class:
2611 * Creates a copy of the remote_class, adding the provided class or interface
2613 static MonoRemoteClass*
2614 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2616 MONO_REQ_GC_NEUTRAL_MODE;
2618 MonoRemoteClass *rc;
2619 gpointer* key, *mp_key;
2621 key = create_remote_class_key (remote_class, extra_class);
2622 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2628 mp_key = copy_remote_class_key (domain, key);
2632 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2634 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2635 rc->proxy_class = remote_class->proxy_class;
2636 rc->interface_count = remote_class->interface_count + 1;
2638 // Keep the list of interfaces sorted, since the hash key of
2639 // the remote class depends on this
2640 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2641 if (remote_class->interfaces [i] > extra_class && i == j)
2642 rc->interfaces [j++] = extra_class;
2643 rc->interfaces [j] = remote_class->interfaces [i];
2646 rc->interfaces [j] = extra_class;
2648 // Replace the old class. The interface array is the same
2649 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2650 rc->proxy_class = extra_class;
2651 rc->interface_count = remote_class->interface_count;
2652 if (rc->interface_count > 0)
2653 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2656 rc->default_vtable = NULL;
2657 rc->xdomain_vtable = NULL;
2658 rc->proxy_class_name = remote_class->proxy_class_name;
2660 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2666 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2668 MONO_REQ_GC_UNSAFE_MODE;
2670 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2671 mono_domain_lock (domain);
2672 if (rp->target_domain_id != -1) {
2673 if (remote_class->xdomain_vtable == NULL)
2674 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2675 mono_domain_unlock (domain);
2676 mono_loader_unlock ();
2677 return remote_class->xdomain_vtable;
2679 if (remote_class->default_vtable == NULL) {
2682 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2683 klass = mono_class_from_mono_type (type);
2685 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)))
2686 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2689 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2692 mono_domain_unlock (domain);
2693 mono_loader_unlock ();
2694 return remote_class->default_vtable;
2698 * mono_upgrade_remote_class:
2699 * @domain: the application domain
2700 * @tproxy: the proxy whose remote class has to be upgraded.
2701 * @klass: class to which the remote class can be casted.
2703 * Updates the vtable of the remote class by adding the necessary method slots
2704 * and interface offsets so it can be safely casted to klass. klass can be a
2705 * class or an interface.
2708 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2710 MONO_REQ_GC_UNSAFE_MODE;
2712 MonoTransparentProxy *tproxy;
2713 MonoRemoteClass *remote_class;
2714 gboolean redo_vtable;
2716 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2717 mono_domain_lock (domain);
2719 tproxy = (MonoTransparentProxy*) proxy_object;
2720 remote_class = tproxy->remote_class;
2722 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2725 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2726 if (remote_class->interfaces [i] == klass)
2727 redo_vtable = FALSE;
2730 redo_vtable = (remote_class->proxy_class != klass);
2734 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2735 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2738 mono_domain_unlock (domain);
2739 mono_loader_unlock ();
2741 #endif /* DISABLE_REMOTING */
2745 * mono_object_get_virtual_method:
2746 * @obj: object to operate on.
2749 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2750 * the instance of a callvirt of method.
2753 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2755 MONO_REQ_GC_UNSAFE_MODE;
2758 MonoMethod **vtable;
2759 gboolean is_proxy = FALSE;
2760 MonoMethod *res = NULL;
2762 klass = mono_object_class (obj);
2763 #ifndef DISABLE_REMOTING
2764 if (klass == mono_defaults.transparent_proxy_class) {
2765 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2770 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2773 mono_class_setup_vtable (klass);
2774 vtable = klass->vtable;
2776 if (method->slot == -1) {
2777 /* method->slot might not be set for instances of generic methods */
2778 if (method->is_inflated) {
2779 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2780 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2783 g_assert_not_reached ();
2787 /* check method->slot is a valid index: perform isinstance? */
2788 if (method->slot != -1) {
2789 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2791 gboolean variance_used = FALSE;
2792 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2793 g_assert (iface_offset > 0);
2794 res = vtable [iface_offset + method->slot];
2797 res = vtable [method->slot];
2801 #ifndef DISABLE_REMOTING
2803 /* It may be an interface, abstract class method or generic method */
2804 if (!res || mono_method_signature (res)->generic_param_count)
2807 /* generic methods demand invoke_with_check */
2808 if (mono_method_signature (res)->generic_param_count)
2809 res = mono_marshal_get_remoting_invoke_with_check (res);
2812 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2813 res = mono_cominterop_get_invoke (res);
2816 res = mono_marshal_get_remoting_invoke (res);
2821 if (method->is_inflated) {
2823 /* Have to inflate the result */
2824 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, &error);
2825 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
2835 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2837 g_error ("runtime invoke called on uninitialized runtime");
2841 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2844 * mono_runtime_invoke:
2845 * @method: method to invoke
2846 * @obJ: object instance
2847 * @params: arguments to the method
2848 * @exc: exception information.
2850 * Invokes the method represented by @method on the object @obj.
2852 * obj is the 'this' pointer, it should be NULL for static
2853 * methods, a MonoObject* for object instances and a pointer to
2854 * the value type for value types.
2856 * The params array contains the arguments to the method with the
2857 * same convention: MonoObject* pointers for object instances and
2858 * pointers to the value type otherwise.
2860 * From unmanaged code you'll usually use the
2861 * mono_runtime_invoke() variant.
2863 * Note that this function doesn't handle virtual methods for
2864 * you, it will exec the exact method you pass: we still need to
2865 * expose a function to lookup the derived class implementation
2866 * of a virtual method (there are examples of this in the code,
2869 * You can pass NULL as the exc argument if you don't want to
2870 * catch exceptions, otherwise, *exc will be set to the exception
2871 * thrown, if any. if an exception is thrown, you can't use the
2872 * MonoObject* result from the function.
2874 * If the method returns a value type, it is boxed in an object
2878 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2880 MONO_REQ_GC_UNSAFE_MODE;
2884 if (mono_runtime_get_no_exec ())
2885 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2887 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2888 mono_profiler_method_start_invoke (method);
2890 result = default_mono_runtime_invoke (method, obj, params, exc);
2892 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2893 mono_profiler_method_end_invoke (method);
2899 * mono_method_get_unmanaged_thunk:
2900 * @method: method to generate a thunk for.
2902 * Returns an unmanaged->managed thunk that can be used to call
2903 * a managed method directly from C.
2905 * The thunk's C signature closely matches the managed signature:
2907 * C#: public bool Equals (object obj);
2908 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2909 * MonoObject*, MonoException**);
2911 * The 1st ("this") parameter must not be used with static methods:
2913 * C#: public static bool ReferenceEquals (object a, object b);
2914 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2917 * The last argument must be a non-null pointer of a MonoException* pointer.
2918 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2919 * exception has been thrown in managed code. Otherwise it will point
2920 * to the MonoException* caught by the thunk. In this case, the result of
2921 * the thunk is undefined:
2923 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2924 * MonoException *ex = NULL;
2925 * Equals func = mono_method_get_unmanaged_thunk (method);
2926 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2928 * // handle exception
2931 * The calling convention of the thunk matches the platform's default
2932 * convention. This means that under Windows, C declarations must
2933 * contain the __stdcall attribute:
2935 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2936 * MonoObject*, MonoException**);
2940 * Value type arguments and return values are treated as they were objects:
2942 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2943 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2945 * Arguments must be properly boxed upon trunk's invocation, while return
2946 * values must be unboxed.
2949 mono_method_get_unmanaged_thunk (MonoMethod *method)
2951 MONO_REQ_GC_NEUTRAL_MODE;
2952 MONO_REQ_API_ENTRYPOINT;
2956 MONO_PREPARE_RESET_BLOCKING
2957 method = mono_marshal_get_thunk_invoke_wrapper (method);
2958 res = mono_compile_method (method);
2959 MONO_FINISH_RESET_BLOCKING
2965 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
2967 MONO_REQ_GC_UNSAFE_MODE;
2971 /* object fields cannot be byref, so we don't need a
2973 gpointer *p = (gpointer*)dest;
2980 case MONO_TYPE_BOOLEAN:
2982 case MONO_TYPE_U1: {
2983 guint8 *p = (guint8*)dest;
2984 *p = value ? *(guint8*)value : 0;
2989 case MONO_TYPE_CHAR: {
2990 guint16 *p = (guint16*)dest;
2991 *p = value ? *(guint16*)value : 0;
2994 #if SIZEOF_VOID_P == 4
2999 case MONO_TYPE_U4: {
3000 gint32 *p = (gint32*)dest;
3001 *p = value ? *(gint32*)value : 0;
3004 #if SIZEOF_VOID_P == 8
3009 case MONO_TYPE_U8: {
3010 gint64 *p = (gint64*)dest;
3011 *p = value ? *(gint64*)value : 0;
3014 case MONO_TYPE_R4: {
3015 float *p = (float*)dest;
3016 *p = value ? *(float*)value : 0;
3019 case MONO_TYPE_R8: {
3020 double *p = (double*)dest;
3021 *p = value ? *(double*)value : 0;
3024 case MONO_TYPE_STRING:
3025 case MONO_TYPE_SZARRAY:
3026 case MONO_TYPE_CLASS:
3027 case MONO_TYPE_OBJECT:
3028 case MONO_TYPE_ARRAY:
3029 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
3031 case MONO_TYPE_FNPTR:
3032 case MONO_TYPE_PTR: {
3033 gpointer *p = (gpointer*)dest;
3034 *p = deref_pointer? *(gpointer*)value: value;
3037 case MONO_TYPE_VALUETYPE:
3038 /* note that 't' and 'type->type' can be different */
3039 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3040 t = mono_class_enum_basetype (type->data.klass)->type;
3043 MonoClass *class = mono_class_from_mono_type (type);
3044 int size = mono_class_value_size (class, NULL);
3046 mono_gc_bzero_atomic (dest, size);
3048 mono_gc_wbarrier_value_copy (dest, value, 1, class);
3051 case MONO_TYPE_GENERICINST:
3052 t = type->data.generic_class->container_class->byval_arg.type;
3055 g_error ("got type %x", type->type);
3060 * mono_field_set_value:
3061 * @obj: Instance object
3062 * @field: MonoClassField describing the field to set
3063 * @value: The value to be set
3065 * Sets the value of the field described by @field in the object instance @obj
3066 * to the value passed in @value. This method should only be used for instance
3067 * fields. For static fields, use mono_field_static_set_value.
3069 * The value must be on the native format of the field type.
3072 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3074 MONO_REQ_GC_UNSAFE_MODE;
3078 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3080 dest = (char*)obj + field->offset;
3081 mono_copy_value (field->type, dest, value, FALSE);
3085 * mono_field_static_set_value:
3086 * @field: MonoClassField describing the field to set
3087 * @value: The value to be set
3089 * Sets the value of the static field described by @field
3090 * to the value passed in @value.
3092 * The value must be on the native format of the field type.
3095 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3097 MONO_REQ_GC_UNSAFE_MODE;
3101 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3102 /* you cant set a constant! */
3103 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3105 if (field->offset == -1) {
3106 /* Special static */
3109 mono_domain_lock (vt->domain);
3110 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3111 mono_domain_unlock (vt->domain);
3112 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3114 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3116 mono_copy_value (field->type, dest, value, FALSE);
3120 * mono_vtable_get_static_field_data:
3122 * Internal use function: return a pointer to the memory holding the static fields
3123 * for a class or NULL if there are no static fields.
3124 * This is exported only for use by the debugger.
3127 mono_vtable_get_static_field_data (MonoVTable *vt)
3129 MONO_REQ_GC_NEUTRAL_MODE
3131 if (!vt->has_static_fields)
3133 return vt->vtable [vt->klass->vtable_size];
3137 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3139 MONO_REQ_GC_UNSAFE_MODE;
3143 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3144 if (field->offset == -1) {
3145 /* Special static */
3148 mono_domain_lock (vt->domain);
3149 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3150 mono_domain_unlock (vt->domain);
3151 src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3153 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3156 src = (guint8*)obj + field->offset;
3163 * mono_field_get_value:
3164 * @obj: Object instance
3165 * @field: MonoClassField describing the field to fetch information from
3166 * @value: pointer to the location where the value will be stored
3168 * Use this routine to get the value of the field @field in the object
3171 * The pointer provided by value must be of the field type, for reference
3172 * types this is a MonoObject*, for value types its the actual pointer to
3177 * mono_field_get_value (obj, int_field, &i);
3180 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3182 MONO_REQ_GC_UNSAFE_MODE;
3188 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3190 src = (char*)obj + field->offset;
3191 mono_copy_value (field->type, value, src, TRUE);
3195 * mono_field_get_value_object:
3196 * @domain: domain where the object will be created (if boxing)
3197 * @field: MonoClassField describing the field to fetch information from
3198 * @obj: The object instance for the field.
3200 * Returns: a new MonoObject with the value from the given field. If the
3201 * field represents a value type, the value is boxed.
3205 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3207 MONO_REQ_GC_UNSAFE_MODE;
3211 MonoVTable *vtable = NULL;
3213 gboolean is_static = FALSE;
3214 gboolean is_ref = FALSE;
3215 gboolean is_literal = FALSE;
3216 gboolean is_ptr = FALSE;
3218 MonoType *type = mono_field_get_type_checked (field, &error);
3220 if (!mono_error_ok (&error))
3221 mono_error_raise_exception (&error);
3223 switch (type->type) {
3224 case MONO_TYPE_STRING:
3225 case MONO_TYPE_OBJECT:
3226 case MONO_TYPE_CLASS:
3227 case MONO_TYPE_ARRAY:
3228 case MONO_TYPE_SZARRAY:
3233 case MONO_TYPE_BOOLEAN:
3236 case MONO_TYPE_CHAR:
3245 case MONO_TYPE_VALUETYPE:
3246 is_ref = type->byref;
3248 case MONO_TYPE_GENERICINST:
3249 is_ref = !mono_type_generic_inst_is_valuetype (type);
3255 g_error ("type 0x%x not handled in "
3256 "mono_field_get_value_object", type->type);
3260 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3263 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3267 vtable = mono_class_vtable_full (domain, field->parent, TRUE);
3268 if (!vtable->initialized)
3269 mono_runtime_class_init (vtable);
3277 get_default_field_value (domain, field, &o);
3278 } else if (is_static) {
3279 mono_field_static_get_value (vtable, field, &o);
3281 mono_field_get_value (obj, field, &o);
3287 static MonoMethod *m;
3293 MonoClass *ptr_klass = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
3294 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3300 get_default_field_value (domain, field, v);
3301 } else if (is_static) {
3302 mono_field_static_get_value (vtable, field, v);
3304 mono_field_get_value (obj, field, v);
3307 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3308 args [0] = ptr ? *ptr : NULL;
3309 args [1] = mono_type_get_object (mono_domain_get (), type);
3311 return mono_runtime_invoke (m, NULL, args, NULL);
3314 /* boxed value type */
3315 klass = mono_class_from_mono_type (type);
3317 if (mono_class_is_nullable (klass))
3318 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
3320 o = mono_object_new (domain, klass);
3321 v = ((gchar *) o) + sizeof (MonoObject);
3324 get_default_field_value (domain, field, v);
3325 } else if (is_static) {
3326 mono_field_static_get_value (vtable, field, v);
3328 mono_field_get_value (obj, field, v);
3335 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
3337 MONO_REQ_GC_UNSAFE_MODE;
3340 const char *p = blob;
3341 mono_metadata_decode_blob_size (p, &p);
3344 case MONO_TYPE_BOOLEAN:
3347 *(guint8 *) value = *p;
3349 case MONO_TYPE_CHAR:
3352 *(guint16*) value = read16 (p);
3356 *(guint32*) value = read32 (p);
3360 *(guint64*) value = read64 (p);
3363 readr4 (p, (float*) value);
3366 readr8 (p, (double*) value);
3368 case MONO_TYPE_STRING:
3369 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3371 case MONO_TYPE_CLASS:
3372 *(gpointer*) value = NULL;
3376 g_warning ("type 0x%02x should not be in constant table", type);
3382 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3384 MONO_REQ_GC_NEUTRAL_MODE;
3386 MonoTypeEnum def_type;
3389 data = mono_class_get_field_default_value (field, &def_type);
3390 mono_get_constant_value_from_blob (domain, def_type, data, value);
3394 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value)
3396 MONO_REQ_GC_UNSAFE_MODE;
3400 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3402 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3403 get_default_field_value (vt->domain, field, value);
3407 if (field->offset == -1) {
3408 /* Special static */
3409 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3410 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3412 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3414 mono_copy_value (field->type, value, src, TRUE);
3418 * mono_field_static_get_value:
3419 * @vt: vtable to the object
3420 * @field: MonoClassField describing the field to fetch information from
3421 * @value: where the value is returned
3423 * Use this routine to get the value of the static field @field value.
3425 * The pointer provided by value must be of the field type, for reference
3426 * types this is a MonoObject*, for value types its the actual pointer to
3431 * mono_field_static_get_value (vt, int_field, &i);
3434 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3436 MONO_REQ_GC_NEUTRAL_MODE;
3438 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value);
3442 * mono_property_set_value:
3443 * @prop: MonoProperty to set
3444 * @obj: instance object on which to act
3445 * @params: parameters to pass to the propery
3446 * @exc: optional exception
3448 * Invokes the property's set method with the given arguments on the
3449 * object instance obj (or NULL for static properties).
3451 * You can pass NULL as the exc argument if you don't want to
3452 * catch exceptions, otherwise, *exc will be set to the exception
3453 * thrown, if any. if an exception is thrown, you can't use the
3454 * MonoObject* result from the function.
3457 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3459 MONO_REQ_GC_UNSAFE_MODE;
3461 default_mono_runtime_invoke (prop->set, obj, params, exc);
3465 * mono_property_get_value:
3466 * @prop: MonoProperty to fetch
3467 * @obj: instance object on which to act
3468 * @params: parameters to pass to the propery
3469 * @exc: optional exception
3471 * Invokes the property's get method with the given arguments on the
3472 * object instance obj (or NULL for static properties).
3474 * You can pass NULL as the exc argument if you don't want to
3475 * catch exceptions, otherwise, *exc will be set to the exception
3476 * thrown, if any. if an exception is thrown, you can't use the
3477 * MonoObject* result from the function.
3479 * Returns: the value from invoking the get method on the property.
3482 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3484 MONO_REQ_GC_UNSAFE_MODE;
3486 return default_mono_runtime_invoke (prop->get, obj, params, exc);
3490 * mono_nullable_init:
3491 * @buf: The nullable structure to initialize.
3492 * @value: the value to initialize from
3493 * @klass: the type for the object
3495 * Initialize the nullable structure pointed to by @buf from @value which
3496 * should be a boxed value type. The size of @buf should be able to hold
3497 * as much data as the @klass->instance_size (which is the number of bytes
3498 * that will be copies).
3500 * Since Nullables have variable structure, we can not define a C
3501 * structure for them.
3504 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3506 MONO_REQ_GC_UNSAFE_MODE;
3508 MonoClass *param_class = klass->cast_class;
3510 mono_class_setup_fields_locking (klass);
3511 g_assert (klass->fields_inited);
3513 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3514 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3516 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3518 if (param_class->has_references)
3519 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3521 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3523 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3528 * mono_nullable_box:
3529 * @buf: The buffer representing the data to be boxed
3530 * @klass: the type to box it as.
3532 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3536 mono_nullable_box (guint8 *buf, MonoClass *klass)
3538 MONO_REQ_GC_UNSAFE_MODE;
3540 MonoClass *param_class = klass->cast_class;
3542 mono_class_setup_fields_locking (klass);
3543 g_assert (klass->fields_inited);
3545 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3546 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3548 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3549 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
3550 if (param_class->has_references)
3551 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3553 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3561 * mono_get_delegate_invoke:
3562 * @klass: The delegate class
3564 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3567 mono_get_delegate_invoke (MonoClass *klass)
3569 MONO_REQ_GC_NEUTRAL_MODE;
3573 /* This is called at runtime, so avoid the slower search in metadata */
3574 mono_class_setup_methods (klass);
3575 if (klass->exception_type)
3577 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3582 * mono_get_delegate_begin_invoke:
3583 * @klass: The delegate class
3585 * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3588 mono_get_delegate_begin_invoke (MonoClass *klass)
3590 MONO_REQ_GC_NEUTRAL_MODE;
3594 /* This is called at runtime, so avoid the slower search in metadata */
3595 mono_class_setup_methods (klass);
3596 if (klass->exception_type)
3598 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3603 * mono_get_delegate_end_invoke:
3604 * @klass: The delegate class
3606 * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3609 mono_get_delegate_end_invoke (MonoClass *klass)
3611 MONO_REQ_GC_NEUTRAL_MODE;
3615 /* This is called at runtime, so avoid the slower search in metadata */
3616 mono_class_setup_methods (klass);
3617 if (klass->exception_type)
3619 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3624 * mono_runtime_delegate_invoke:
3625 * @delegate: pointer to a delegate object.
3626 * @params: parameters for the delegate.
3627 * @exc: Pointer to the exception result.
3629 * Invokes the delegate method @delegate with the parameters provided.
3631 * You can pass NULL as the exc argument if you don't want to
3632 * catch exceptions, otherwise, *exc will be set to the exception
3633 * thrown, if any. if an exception is thrown, you can't use the
3634 * MonoObject* result from the function.
3637 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3639 MONO_REQ_GC_UNSAFE_MODE;
3642 MonoClass *klass = delegate->vtable->klass;
3644 im = mono_get_delegate_invoke (klass);
3646 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3648 return mono_runtime_invoke (im, delegate, params, exc);
3651 static char **main_args = NULL;
3652 static int num_main_args = 0;
3655 * mono_runtime_get_main_args:
3657 * Returns: a MonoArray with the arguments passed to the main program
3660 mono_runtime_get_main_args (void)
3662 MONO_REQ_GC_UNSAFE_MODE;
3666 MonoDomain *domain = mono_domain_get ();
3668 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3670 for (i = 0; i < num_main_args; ++i)
3671 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3677 free_main_args (void)
3679 MONO_REQ_GC_NEUTRAL_MODE;
3683 for (i = 0; i < num_main_args; ++i)
3684 g_free (main_args [i]);
3691 * mono_runtime_set_main_args:
3692 * @argc: number of arguments from the command line
3693 * @argv: array of strings from the command line
3695 * Set the command line arguments from an embedding application that doesn't otherwise call
3696 * mono_runtime_run_main ().
3699 mono_runtime_set_main_args (int argc, char* argv[])
3701 MONO_REQ_GC_NEUTRAL_MODE;
3706 main_args = g_new0 (char*, argc);
3707 num_main_args = argc;
3709 for (i = 0; i < argc; ++i) {
3712 utf8_arg = mono_utf8_from_external (argv[i]);
3713 if (utf8_arg == NULL) {
3714 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
3715 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3719 main_args [i] = utf8_arg;
3726 * mono_runtime_run_main:
3727 * @method: the method to start the application with (usually Main)
3728 * @argc: number of arguments from the command line
3729 * @argv: array of strings from the command line
3730 * @exc: excetption results
3732 * Execute a standard Main() method (argc/argv contains the
3733 * executable name). This method also sets the command line argument value
3734 * needed by System.Environment.
3739 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3742 MONO_REQ_GC_UNSAFE_MODE;
3745 MonoArray *args = NULL;
3746 MonoDomain *domain = mono_domain_get ();
3747 gchar *utf8_fullpath;
3748 MonoMethodSignature *sig;
3750 g_assert (method != NULL);
3752 mono_thread_set_main (mono_thread_current ());
3754 main_args = g_new0 (char*, argc);
3755 num_main_args = argc;
3757 if (!g_path_is_absolute (argv [0])) {
3758 gchar *basename = g_path_get_basename (argv [0]);
3759 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3763 utf8_fullpath = mono_utf8_from_external (fullpath);
3764 if(utf8_fullpath == NULL) {
3765 /* Printing the arg text will cause glib to
3766 * whinge about "Invalid UTF-8", but at least
3767 * its relevant, and shows the problem text
3770 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3771 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3778 utf8_fullpath = mono_utf8_from_external (argv[0]);
3779 if(utf8_fullpath == NULL) {
3780 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3781 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3786 main_args [0] = utf8_fullpath;
3788 for (i = 1; i < argc; ++i) {
3791 utf8_arg=mono_utf8_from_external (argv[i]);
3792 if(utf8_arg==NULL) {
3793 /* Ditto the comment about Invalid UTF-8 here */
3794 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3795 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3799 main_args [i] = utf8_arg;
3804 sig = mono_method_signature (method);
3806 g_print ("Unable to load Main method.\n");
3810 if (sig->param_count) {
3811 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3812 for (i = 0; i < argc; ++i) {
3813 /* The encodings should all work, given that
3814 * we've checked all these args for the
3817 gchar *str = mono_utf8_from_external (argv [i]);
3818 MonoString *arg = mono_string_new (domain, str);
3819 mono_array_setref (args, i, arg);
3823 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3826 mono_assembly_set_main (method->klass->image->assembly);
3828 return mono_runtime_exec_main (method, args, exc);
3832 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3834 static MonoMethod *serialize_method;
3839 if (!serialize_method) {
3840 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3841 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
3844 if (!serialize_method) {
3849 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
3853 array = mono_runtime_invoke (serialize_method, NULL, params, exc);
3861 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3863 MONO_REQ_GC_UNSAFE_MODE;
3865 static MonoMethod *deserialize_method;
3870 if (!deserialize_method) {
3871 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3872 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
3874 if (!deserialize_method) {
3881 result = mono_runtime_invoke (deserialize_method, NULL, params, exc);
3888 #ifndef DISABLE_REMOTING
3890 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
3892 MONO_REQ_GC_UNSAFE_MODE;
3894 static MonoMethod *get_proxy_method;
3896 MonoDomain *domain = mono_domain_get ();
3897 MonoRealProxy *real_proxy;
3898 MonoReflectionType *reflection_type;
3899 MonoTransparentProxy *transparent_proxy;
3901 if (!get_proxy_method)
3902 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
3904 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
3906 real_proxy = (MonoRealProxy*) mono_object_new (domain, mono_defaults.real_proxy_class);
3907 reflection_type = mono_type_get_object (domain, &obj->vtable->klass->byval_arg);
3909 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
3910 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
3913 transparent_proxy = (MonoTransparentProxy*) mono_runtime_invoke (get_proxy_method, real_proxy, NULL, exc);
3917 return (MonoObject*) transparent_proxy;
3919 #endif /* DISABLE_REMOTING */
3922 * mono_object_xdomain_representation
3924 * @target_domain: a domain
3925 * @exc: pointer to a MonoObject*
3927 * Creates a representation of obj in the domain target_domain. This
3928 * is either a copy of obj arrived through via serialization and
3929 * deserialization or a proxy, depending on whether the object is
3930 * serializable or marshal by ref. obj must not be in target_domain.
3932 * If the object cannot be represented in target_domain, NULL is
3933 * returned and *exc is set to an appropriate exception.
3936 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
3938 MONO_REQ_GC_UNSAFE_MODE;
3940 MonoObject *deserialized = NULL;
3941 gboolean failure = FALSE;
3945 #ifndef DISABLE_REMOTING
3946 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
3947 deserialized = make_transparent_proxy (obj, &failure, exc);
3952 MonoDomain *domain = mono_domain_get ();
3953 MonoObject *serialized;
3955 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
3956 serialized = serialize_object (obj, &failure, exc);
3957 mono_domain_set_internal_with_options (target_domain, FALSE);
3959 deserialized = deserialize_object (serialized, &failure, exc);
3960 if (domain != target_domain)
3961 mono_domain_set_internal_with_options (domain, FALSE);
3964 return deserialized;
3967 /* Used in call_unhandled_exception_delegate */
3969 create_unhandled_exception_eventargs (MonoObject *exc)
3971 MONO_REQ_GC_UNSAFE_MODE;
3975 MonoMethod *method = NULL;
3976 MonoBoolean is_terminating = TRUE;
3979 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
3982 mono_class_init (klass);
3984 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
3985 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
3989 args [1] = &is_terminating;
3991 obj = mono_object_new (mono_domain_get (), klass);
3992 mono_runtime_invoke (method, obj, args, NULL);
3997 /* Used in mono_unhandled_exception */
3999 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4000 MONO_REQ_GC_UNSAFE_MODE;
4002 MonoObject *e = NULL;
4004 MonoDomain *current_domain = mono_domain_get ();
4006 if (domain != current_domain)
4007 mono_domain_set_internal_with_options (domain, FALSE);
4009 g_assert (domain == mono_object_domain (domain->domain));
4011 if (mono_object_domain (exc) != domain) {
4012 MonoObject *serialization_exc;
4014 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
4016 if (serialization_exc) {
4018 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
4021 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4022 "System.Runtime.Serialization", "SerializationException",
4023 "Could not serialize unhandled exception.");
4027 g_assert (mono_object_domain (exc) == domain);
4029 pa [0] = domain->domain;
4030 pa [1] = create_unhandled_exception_eventargs (exc);
4031 mono_runtime_delegate_invoke (delegate, pa, &e);
4033 if (domain != current_domain)
4034 mono_domain_set_internal_with_options (current_domain, FALSE);
4038 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4039 if (!mono_error_ok (&error)) {
4040 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4041 mono_error_cleanup (&error);
4043 g_warning ("exception inside UnhandledException handler: %s\n", msg);
4049 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4052 * mono_runtime_unhandled_exception_policy_set:
4053 * @policy: the new policy
4055 * This is a VM internal routine.
4057 * Sets the runtime policy for handling unhandled exceptions.
4060 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4061 runtime_unhandled_exception_policy = policy;
4065 * mono_runtime_unhandled_exception_policy_get:
4067 * This is a VM internal routine.
4069 * Gets the runtime policy for handling unhandled exceptions.
4071 MonoRuntimeUnhandledExceptionPolicy
4072 mono_runtime_unhandled_exception_policy_get (void) {
4073 return runtime_unhandled_exception_policy;
4077 * mono_unhandled_exception:
4078 * @exc: exception thrown
4080 * This is a VM internal routine.
4082 * We call this function when we detect an unhandled exception
4083 * in the default domain.
4085 * It invokes the * UnhandledException event in AppDomain or prints
4086 * a warning to the console
4089 mono_unhandled_exception (MonoObject *exc)
4091 MONO_REQ_GC_UNSAFE_MODE;
4093 MonoClassField *field;
4094 MonoDomain *current_domain, *root_domain;
4095 MonoObject *current_appdomain_delegate = NULL, *root_appdomain_delegate = NULL;
4097 if (mono_class_has_parent (exc->vtable->klass, mono_defaults.threadabortexception_class))
4100 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4103 current_domain = mono_domain_get ();
4104 root_domain = mono_get_root_domain ();
4106 root_appdomain_delegate = mono_field_get_value_object (root_domain, field, (MonoObject*) root_domain->domain);
4107 if (current_domain != root_domain)
4108 current_appdomain_delegate = mono_field_get_value_object (current_domain, field, (MonoObject*) current_domain->domain);
4110 /* set exitcode only if we will abort the process */
4111 if (!current_appdomain_delegate && !root_appdomain_delegate) {
4112 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4113 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4115 mono_environment_exitcode_set (1);
4118 mono_print_unhandled_exception (exc);
4120 if (root_appdomain_delegate)
4121 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4122 if (current_appdomain_delegate)
4123 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4128 * mono_runtime_exec_managed_code:
4129 * @domain: Application domain
4130 * @main_func: function to invoke from the execution thread
4131 * @main_args: parameter to the main_func
4133 * Launch a new thread to execute a function
4135 * main_func is called back from the thread with main_args as the
4136 * parameter. The callback function is expected to start Main()
4137 * eventually. This function then waits for all managed threads to
4139 * It is not necesseray anymore to execute managed code in a subthread,
4140 * so this function should not be used anymore by default: just
4141 * execute the code and then call mono_thread_manage ().
4144 mono_runtime_exec_managed_code (MonoDomain *domain,
4145 MonoMainThreadFunc main_func,
4148 mono_thread_create (domain, main_func, main_args);
4150 mono_thread_manage ();
4154 * Execute a standard Main() method (args doesn't contain the
4158 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4160 MONO_REQ_GC_UNSAFE_MODE;
4165 MonoCustomAttrInfo* cinfo;
4166 gboolean has_stathread_attribute;
4167 MonoInternalThread* thread = mono_thread_internal_current ();
4173 domain = mono_object_domain (args);
4174 if (!domain->entry_assembly) {
4176 MonoAssembly *assembly;
4178 assembly = method->klass->image->assembly;
4179 domain->entry_assembly = assembly;
4180 /* Domains created from another domain already have application_base and configuration_file set */
4181 if (domain->setup->application_base == NULL) {
4182 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4185 if (domain->setup->configuration_file == NULL) {
4186 str = g_strconcat (assembly->image->name, ".config", NULL);
4187 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4189 mono_set_private_bin_path_from_config (domain);
4193 cinfo = mono_custom_attrs_from_method (method);
4195 static MonoClass *stathread_attribute = NULL;
4196 if (!stathread_attribute)
4197 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
4198 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
4200 mono_custom_attrs_free (cinfo);
4202 has_stathread_attribute = FALSE;
4204 if (has_stathread_attribute) {
4205 thread->apartment_state = ThreadApartmentState_STA;
4207 thread->apartment_state = ThreadApartmentState_MTA;
4209 mono_thread_init_apartment_state ();
4211 /* FIXME: check signature of method */
4212 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4214 res = mono_runtime_invoke (method, NULL, pa, exc);
4216 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4220 mono_environment_exitcode_set (rval);
4222 mono_runtime_invoke (method, NULL, pa, exc);
4226 /* If the return type of Main is void, only
4227 * set the exitcode if an exception was thrown
4228 * (we don't want to blow away an
4229 * explicitly-set exit code)
4232 mono_environment_exitcode_set (rval);
4240 * mono_install_runtime_invoke:
4241 * @func: Function to install
4243 * This is a VM internal routine
4246 mono_install_runtime_invoke (MonoInvokeFunc func)
4248 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
4253 * mono_runtime_invoke_array:
4254 * @method: method to invoke
4255 * @obJ: object instance
4256 * @params: arguments to the method
4257 * @exc: exception information.
4259 * Invokes the method represented by @method on the object @obj.
4261 * obj is the 'this' pointer, it should be NULL for static
4262 * methods, a MonoObject* for object instances and a pointer to
4263 * the value type for value types.
4265 * The params array contains the arguments to the method with the
4266 * same convention: MonoObject* pointers for object instances and
4267 * pointers to the value type otherwise. The _invoke_array
4268 * variant takes a C# object[] as the params argument (MonoArray
4269 * *params): in this case the value types are boxed inside the
4270 * respective reference representation.
4272 * From unmanaged code you'll usually use the
4273 * mono_runtime_invoke() variant.
4275 * Note that this function doesn't handle virtual methods for
4276 * you, it will exec the exact method you pass: we still need to
4277 * expose a function to lookup the derived class implementation
4278 * of a virtual method (there are examples of this in the code,
4281 * You can pass NULL as the exc argument if you don't want to
4282 * catch exceptions, otherwise, *exc will be set to the exception
4283 * thrown, if any. if an exception is thrown, you can't use the
4284 * MonoObject* result from the function.
4286 * If the method returns a value type, it is boxed in an object
4290 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4293 MONO_REQ_GC_UNSAFE_MODE;
4295 MonoMethodSignature *sig = mono_method_signature (method);
4296 gpointer *pa = NULL;
4299 gboolean has_byref_nullables = FALSE;
4301 if (NULL != params) {
4302 pa = alloca (sizeof (gpointer) * mono_array_length (params));
4303 for (i = 0; i < mono_array_length (params); i++) {
4304 MonoType *t = sig->params [i];
4310 case MONO_TYPE_BOOLEAN:
4313 case MONO_TYPE_CHAR:
4322 case MONO_TYPE_VALUETYPE:
4323 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
4324 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4325 pa [i] = mono_array_get (params, MonoObject*, i);
4327 has_byref_nullables = TRUE;
4329 /* MS seems to create the objects if a null is passed in */
4330 if (!mono_array_get (params, MonoObject*, i))
4331 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
4335 * We can't pass the unboxed vtype byref to the callee, since
4336 * that would mean the callee would be able to modify boxed
4337 * primitive types. So we (and MS) make a copy of the boxed
4338 * object, pass that to the callee, and replace the original
4339 * boxed object in the arg array with the copy.
4341 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4342 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
4343 mono_array_setref (params, i, copy);
4346 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4349 case MONO_TYPE_STRING:
4350 case MONO_TYPE_OBJECT:
4351 case MONO_TYPE_CLASS:
4352 case MONO_TYPE_ARRAY:
4353 case MONO_TYPE_SZARRAY:
4355 pa [i] = mono_array_addr (params, MonoObject*, i);
4356 // FIXME: I need to check this code path
4358 pa [i] = mono_array_get (params, MonoObject*, i);
4360 case MONO_TYPE_GENERICINST:
4362 t = &t->data.generic_class->container_class->this_arg;
4364 t = &t->data.generic_class->container_class->byval_arg;
4366 case MONO_TYPE_PTR: {
4369 /* The argument should be an IntPtr */
4370 arg = mono_array_get (params, MonoObject*, i);
4374 g_assert (arg->vtable->klass == mono_defaults.int_class);
4375 pa [i] = ((MonoIntPtr*)arg)->m_value;
4380 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
4385 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4388 if (mono_class_is_nullable (method->klass)) {
4389 /* Need to create a boxed vtype instead */
4395 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
4399 obj = mono_object_new (mono_domain_get (), method->klass);
4400 g_assert (obj); /*maybe we should raise a TLE instead?*/
4401 #ifndef DISABLE_REMOTING
4402 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
4403 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
4406 if (method->klass->valuetype)
4407 o = mono_object_unbox (obj);
4410 } else if (method->klass->valuetype) {
4411 obj = mono_value_box (mono_domain_get (), method->klass, obj);
4414 mono_runtime_invoke (method, o, pa, exc);
4417 if (mono_class_is_nullable (method->klass)) {
4418 MonoObject *nullable;
4420 /* Convert the unboxed vtype into a Nullable structure */
4421 nullable = mono_object_new (mono_domain_get (), method->klass);
4423 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
4424 obj = mono_object_unbox (nullable);
4427 /* obj must be already unboxed if needed */
4428 res = mono_runtime_invoke (method, obj, pa, exc);
4430 if (sig->ret->type == MONO_TYPE_PTR) {
4431 MonoClass *pointer_class;
4432 static MonoMethod *box_method;
4434 MonoObject *box_exc;
4437 * The runtime-invoke wrapper returns a boxed IntPtr, need to
4438 * convert it to a Pointer object.
4440 pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
4442 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4444 g_assert (res->vtable->klass == mono_defaults.int_class);
4445 box_args [0] = ((MonoIntPtr*)res)->m_value;
4446 box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
4447 res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
4448 g_assert (!box_exc);
4451 if (has_byref_nullables) {
4453 * The runtime invoke wrapper already converted byref nullables back,
4454 * and stored them in pa, we just need to copy them back to the
4457 for (i = 0; i < mono_array_length (params); i++) {
4458 MonoType *t = sig->params [i];
4460 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4461 mono_array_setref (params, i, pa [i]);
4470 arith_overflow (void)
4472 MONO_REQ_GC_UNSAFE_MODE;
4474 mono_raise_exception (mono_get_exception_overflow ());
4479 * @klass: the class of the object that we want to create
4481 * Returns: a newly created object whose definition is
4482 * looked up using @klass. This will not invoke any constructors,
4483 * so the consumer of this routine has to invoke any constructors on
4484 * its own to initialize the object.
4486 * It returns NULL on failure.
4489 mono_object_new (MonoDomain *domain, MonoClass *klass)
4491 MONO_REQ_GC_UNSAFE_MODE;
4495 vtable = mono_class_vtable (domain, klass);
4498 return mono_object_new_specific (vtable);
4502 * mono_object_new_pinned:
4504 * Same as mono_object_new, but the returned object will be pinned.
4505 * For SGEN, these objects will only be freed at appdomain unload.
4508 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass)
4510 MONO_REQ_GC_UNSAFE_MODE;
4514 vtable = mono_class_vtable (domain, klass);
4519 return mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
4521 return mono_object_new_specific (vtable);
4526 * mono_object_new_specific:
4527 * @vtable: the vtable of the object that we want to create
4529 * Returns: A newly created object with class and domain specified
4533 mono_object_new_specific (MonoVTable *vtable)
4535 MONO_REQ_GC_UNSAFE_MODE;
4539 /* check for is_com_object for COM Interop */
4540 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
4543 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4546 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
4549 mono_class_init (klass);
4551 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4553 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
4554 vtable->domain->create_proxy_for_type_method = im;
4557 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
4559 o = mono_runtime_invoke (im, NULL, pa, NULL);
4560 if (o != NULL) return o;
4563 return mono_object_new_alloc_specific (vtable);
4567 mono_object_new_alloc_specific (MonoVTable *vtable)
4569 MONO_REQ_GC_UNSAFE_MODE;
4571 MonoObject *o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
4573 if (G_UNLIKELY (vtable->klass->has_finalize))
4574 mono_object_register_finalizer (o);
4580 mono_object_new_fast (MonoVTable *vtable)
4582 MONO_REQ_GC_UNSAFE_MODE;
4584 return mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
4588 * mono_class_get_allocation_ftn:
4590 * @for_box: the object will be used for boxing
4591 * @pass_size_in_words:
4593 * Return the allocation function appropriate for the given class.
4597 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
4599 MONO_REQ_GC_NEUTRAL_MODE;
4601 *pass_size_in_words = FALSE;
4603 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass) || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4604 return mono_object_new_specific;
4606 if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
4608 return mono_object_new_fast;
4611 * FIXME: This is actually slower than mono_object_new_fast, because
4612 * of the overhead of parameter passing.
4615 *pass_size_in_words = TRUE;
4616 #ifdef GC_REDIRECT_TO_LOCAL
4617 return GC_local_gcj_fast_malloc;
4619 return GC_gcj_fast_malloc;
4624 return mono_object_new_specific;
4628 * mono_object_new_from_token:
4629 * @image: Context where the type_token is hosted
4630 * @token: a token of the type that we want to create
4632 * Returns: A newly created object whose definition is
4633 * looked up using @token in the @image image
4636 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
4638 MONO_REQ_GC_UNSAFE_MODE;
4643 class = mono_class_get_checked (image, token, &error);
4644 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
4646 return mono_object_new (domain, class);
4651 * mono_object_clone:
4652 * @obj: the object to clone
4654 * Returns: A newly created object who is a shallow copy of @obj
4657 mono_object_clone (MonoObject *obj)
4659 MONO_REQ_GC_UNSAFE_MODE;
4662 int size = obj->vtable->klass->instance_size;
4664 if (obj->vtable->klass->rank)
4665 return (MonoObject*)mono_array_clone ((MonoArray*)obj);
4667 o = mono_gc_alloc_obj (obj->vtable, size);
4669 /* If the object doesn't contain references this will do a simple memmove. */
4670 mono_gc_wbarrier_object_copy (o, obj);
4672 if (obj->vtable->klass->has_finalize)
4673 mono_object_register_finalizer (o);
4678 * mono_array_full_copy:
4679 * @src: source array to copy
4680 * @dest: destination array
4682 * Copies the content of one array to another with exactly the same type and size.
4685 mono_array_full_copy (MonoArray *src, MonoArray *dest)
4687 MONO_REQ_GC_UNSAFE_MODE;
4690 MonoClass *klass = src->obj.vtable->klass;
4692 g_assert (klass == dest->obj.vtable->klass);
4694 size = mono_array_length (src);
4695 g_assert (size == mono_array_length (dest));
4696 size *= mono_array_element_size (klass);
4698 if (klass->element_class->valuetype) {
4699 if (klass->element_class->has_references)
4700 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
4702 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
4704 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
4707 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
4712 * mono_array_clone_in_domain:
4713 * @domain: the domain in which the array will be cloned into
4714 * @array: the array to clone
4716 * This routine returns a copy of the array that is hosted on the
4717 * specified MonoDomain.
4720 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
4722 MONO_REQ_GC_UNSAFE_MODE;
4727 MonoClass *klass = array->obj.vtable->klass;
4729 if (array->bounds == NULL) {
4730 size = mono_array_length (array);
4731 o = mono_array_new_full (domain, klass, &size, NULL);
4733 size *= mono_array_element_size (klass);
4735 if (klass->element_class->valuetype) {
4736 if (klass->element_class->has_references)
4737 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
4739 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4741 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4744 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4749 sizes = alloca (klass->rank * sizeof(intptr_t) * 2);
4750 size = mono_array_element_size (klass);
4751 for (i = 0; i < klass->rank; ++i) {
4752 sizes [i] = array->bounds [i].length;
4753 size *= array->bounds [i].length;
4754 sizes [i + klass->rank] = array->bounds [i].lower_bound;
4756 o = mono_array_new_full (domain, klass, sizes, (intptr_t*)sizes + klass->rank);
4758 if (klass->element_class->valuetype) {
4759 if (klass->element_class->has_references)
4760 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
4762 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4764 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4767 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4775 * @array: the array to clone
4777 * Returns: A newly created array who is a shallow copy of @array
4780 mono_array_clone (MonoArray *array)
4782 MONO_REQ_GC_UNSAFE_MODE;
4784 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
4787 /* helper macros to check for overflow when calculating the size of arrays */
4788 #ifdef MONO_BIG_ARRAYS
4789 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
4790 #define MYGUINT_MAX MYGUINT64_MAX
4791 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4792 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
4793 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4794 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
4795 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
4797 #define MYGUINT32_MAX 4294967295U
4798 #define MYGUINT_MAX MYGUINT32_MAX
4799 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4800 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
4801 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4802 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
4803 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
4807 mono_array_calc_byte_len (MonoClass *class, uintptr_t len, uintptr_t *res)
4809 MONO_REQ_GC_NEUTRAL_MODE;
4813 byte_len = mono_array_element_size (class);
4814 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
4817 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
4819 byte_len += sizeof (MonoArray);
4827 * mono_array_new_full:
4828 * @domain: domain where the object is created
4829 * @array_class: array class
4830 * @lengths: lengths for each dimension in the array
4831 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
4833 * This routine creates a new array objects with the given dimensions,
4834 * lower bounds and type.
4837 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
4839 MONO_REQ_GC_UNSAFE_MODE;
4841 uintptr_t byte_len = 0, len, bounds_size;
4844 MonoArrayBounds *bounds;
4848 if (!array_class->inited)
4849 mono_class_init (array_class);
4853 /* A single dimensional array with a 0 lower bound is the same as an szarray */
4854 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
4856 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
4860 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
4862 for (i = 0; i < array_class->rank; ++i) {
4863 if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
4865 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
4866 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4871 if (!mono_array_calc_byte_len (array_class, len, &byte_len))
4872 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4876 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
4877 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4878 byte_len = (byte_len + 3) & ~3;
4879 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
4880 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4881 byte_len += bounds_size;
4884 * Following three lines almost taken from mono_object_new ():
4885 * they need to be kept in sync.
4887 vtable = mono_class_vtable_full (domain, array_class, TRUE);
4889 o = mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
4891 o = mono_gc_alloc_vector (vtable, byte_len, len);
4892 array = (MonoArray*)o;
4894 bounds = array->bounds;
4897 for (i = 0; i < array_class->rank; ++i) {
4898 bounds [i].length = lengths [i];
4900 bounds [i].lower_bound = lower_bounds [i];
4909 * @domain: domain where the object is created
4910 * @eclass: element class
4911 * @n: number of array elements
4913 * This routine creates a new szarray with @n elements of type @eclass.
4916 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
4918 MONO_REQ_GC_UNSAFE_MODE;
4922 ac = mono_array_class_get (eclass, 1);
4925 return mono_array_new_specific (mono_class_vtable_full (domain, ac, TRUE), n);
4929 * mono_array_new_specific:
4930 * @vtable: a vtable in the appropriate domain for an initialized class
4931 * @n: number of array elements
4933 * This routine is a fast alternative to mono_array_new() for code which
4934 * can be sure about the domain it operates in.
4937 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
4939 MONO_REQ_GC_UNSAFE_MODE;
4945 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
4950 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
4951 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4954 o = mono_gc_alloc_vector (vtable, byte_len, n);
4961 * mono_string_new_utf16:
4962 * @text: a pointer to an utf16 string
4963 * @len: the length of the string
4965 * Returns: A newly created string object which contains @text.
4968 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
4970 MONO_REQ_GC_UNSAFE_MODE;
4974 s = mono_string_new_size (domain, len);
4975 g_assert (s != NULL);
4977 memcpy (mono_string_chars (s), text, len * 2);
4983 * mono_string_new_utf32:
4984 * @text: a pointer to an utf32 string
4985 * @len: the length of the string
4987 * Returns: A newly created string object which contains @text.
4990 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
4992 MONO_REQ_GC_UNSAFE_MODE;
4995 mono_unichar2 *utf16_output = NULL;
4996 gint32 utf16_len = 0;
4997 GError *error = NULL;
4998 glong items_written;
5000 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &error);
5003 g_error_free (error);
5005 while (utf16_output [utf16_len]) utf16_len++;
5007 s = mono_string_new_size (domain, utf16_len);
5008 g_assert (s != NULL);
5010 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
5012 g_free (utf16_output);
5018 * mono_string_new_size:
5019 * @text: a pointer to an utf16 string
5020 * @len: the length of the string
5022 * Returns: A newly created string object of @len
5025 mono_string_new_size (MonoDomain *domain, gint32 len)
5027 MONO_REQ_GC_UNSAFE_MODE;
5033 /* check for overflow */
5034 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2))
5035 mono_gc_out_of_memory (-1);
5037 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
5038 g_assert (size > 0);
5040 vtable = mono_class_vtable (domain, mono_defaults.string_class);
5043 s = mono_gc_alloc_string (vtable, size, len);
5049 * mono_string_new_len:
5050 * @text: a pointer to an utf8 string
5051 * @length: number of bytes in @text to consider
5053 * Returns: A newly created string object which contains @text.
5056 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
5058 MONO_REQ_GC_UNSAFE_MODE;
5060 GError *error = NULL;
5061 MonoString *o = NULL;
5063 glong items_written;
5065 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &error);
5068 o = mono_string_new_utf16 (domain, ut, items_written);
5070 g_error_free (error);
5079 * @text: a pointer to an utf8 string
5081 * Returns: A newly created string object which contains @text.
5084 mono_string_new (MonoDomain *domain, const char *text)
5086 MONO_REQ_GC_UNSAFE_MODE;
5088 GError *error = NULL;
5089 MonoString *o = NULL;
5091 glong items_written;
5096 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
5099 o = mono_string_new_utf16 (domain, ut, items_written);
5101 g_error_free (error);
5104 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
5109 MonoString *o = NULL;
5111 if (!g_utf8_validate (text, -1, &end))
5114 len = g_utf8_strlen (text, -1);
5115 o = mono_string_new_size (domain, len);
5116 str = mono_string_chars (o);
5118 while (text < end) {
5119 *str++ = g_utf8_get_char (text);
5120 text = g_utf8_next_char (text);
5127 * mono_string_new_wrapper:
5128 * @text: pointer to utf8 characters.
5130 * Helper function to create a string object from @text in the current domain.
5133 mono_string_new_wrapper (const char *text)
5135 MONO_REQ_GC_UNSAFE_MODE;
5137 MonoDomain *domain = mono_domain_get ();
5140 return mono_string_new (domain, text);
5147 * @class: the class of the value
5148 * @value: a pointer to the unboxed data
5150 * Returns: A newly created object which contains @value.
5153 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
5155 MONO_REQ_GC_UNSAFE_MODE;
5161 g_assert (class->valuetype);
5162 if (mono_class_is_nullable (class))
5163 return mono_nullable_box (value, class);
5165 vtable = mono_class_vtable (domain, class);
5168 size = mono_class_instance_size (class);
5169 res = mono_object_new_alloc_specific (vtable);
5171 size = size - sizeof (MonoObject);
5174 g_assert (size == mono_class_value_size (class, NULL));
5175 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
5177 #if NO_UNALIGNED_ACCESS
5178 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5182 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
5185 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
5188 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
5191 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
5194 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5198 if (class->has_finalize)
5199 mono_object_register_finalizer (res);
5205 * @dest: destination pointer
5206 * @src: source pointer
5207 * @klass: a valuetype class
5209 * Copy a valuetype from @src to @dest. This function must be used
5210 * when @klass contains references fields.
5213 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
5215 MONO_REQ_GC_UNSAFE_MODE;
5217 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
5221 * mono_value_copy_array:
5222 * @dest: destination array
5223 * @dest_idx: index in the @dest array
5224 * @src: source pointer
5225 * @count: number of items
5227 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
5228 * This function must be used when @klass contains references fields.
5229 * Overlap is handled.
5232 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
5234 MONO_REQ_GC_UNSAFE_MODE;
5236 int size = mono_array_element_size (dest->obj.vtable->klass);
5237 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
5238 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
5239 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
5243 * mono_object_get_domain:
5244 * @obj: object to query
5246 * Returns: the MonoDomain where the object is hosted
5249 mono_object_get_domain (MonoObject *obj)
5251 MONO_REQ_GC_UNSAFE_MODE;
5253 return mono_object_domain (obj);
5257 * mono_object_get_class:
5258 * @obj: object to query
5260 * Returns: the MonOClass of the object.
5263 mono_object_get_class (MonoObject *obj)
5265 MONO_REQ_GC_UNSAFE_MODE;
5267 return mono_object_class (obj);
5270 * mono_object_get_size:
5271 * @o: object to query
5273 * Returns: the size, in bytes, of @o
5276 mono_object_get_size (MonoObject* o)
5278 MONO_REQ_GC_UNSAFE_MODE;
5280 MonoClass* klass = mono_object_class (o);
5281 if (klass == mono_defaults.string_class) {
5282 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
5283 } else if (o->vtable->rank) {
5284 MonoArray *array = (MonoArray*)o;
5285 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
5286 if (array->bounds) {
5289 size += sizeof (MonoArrayBounds) * o->vtable->rank;
5293 return mono_class_instance_size (klass);
5298 * mono_object_unbox:
5299 * @obj: object to unbox
5301 * Returns: a pointer to the start of the valuetype boxed in this
5304 * This method will assert if the object passed is not a valuetype.
5307 mono_object_unbox (MonoObject *obj)
5309 MONO_REQ_GC_UNSAFE_MODE;
5311 /* add assert for valuetypes? */
5312 g_assert (obj->vtable->klass->valuetype);
5313 return ((char*)obj) + sizeof (MonoObject);
5317 * mono_object_isinst:
5319 * @klass: a pointer to a class
5321 * Returns: @obj if @obj is derived from @klass
5324 mono_object_isinst (MonoObject *obj, MonoClass *klass)
5326 MONO_REQ_GC_UNSAFE_MODE;
5329 mono_class_init (klass);
5331 if (mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
5332 return mono_object_isinst_mbyref (obj, klass);
5337 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
5341 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
5343 MONO_REQ_GC_UNSAFE_MODE;
5352 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5353 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
5357 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
5358 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
5361 MonoClass *oklass = vt->klass;
5362 if (mono_class_is_transparent_proxy (oklass))
5363 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
5365 mono_class_setup_supertypes (klass);
5366 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
5369 #ifndef DISABLE_REMOTING
5370 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
5372 MonoDomain *domain = mono_domain_get ();
5374 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
5375 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
5376 MonoMethod *im = NULL;
5379 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
5381 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
5382 im = mono_object_get_virtual_method (rp, im);
5385 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
5388 res = mono_runtime_invoke (im, rp, pa, NULL);
5390 if (*(MonoBoolean *) mono_object_unbox(res)) {
5391 /* Update the vtable of the remote type, so it can safely cast to this new type */
5392 mono_upgrade_remote_class (domain, obj, klass);
5396 #endif /* DISABLE_REMOTING */
5401 * mono_object_castclass_mbyref:
5403 * @klass: a pointer to a class
5405 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
5408 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
5410 MONO_REQ_GC_UNSAFE_MODE;
5412 if (!obj) return NULL;
5413 if (mono_object_isinst_mbyref (obj, klass)) return obj;
5415 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
5417 "InvalidCastException"));
5422 MonoDomain *orig_domain;
5428 str_lookup (MonoDomain *domain, gpointer user_data)
5430 MONO_REQ_GC_UNSAFE_MODE;
5432 LDStrInfo *info = user_data;
5433 if (info->res || domain == info->orig_domain)
5435 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
5441 mono_string_get_pinned (MonoString *str)
5443 MONO_REQ_GC_UNSAFE_MODE;
5447 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
5448 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
5450 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
5451 news->length = mono_string_length (str);
5457 #define mono_string_get_pinned(str) (str)
5461 mono_string_is_interned_lookup (MonoString *str, int insert)
5463 MONO_REQ_GC_UNSAFE_MODE;
5465 MonoGHashTable *ldstr_table;
5466 MonoString *s, *res;
5469 domain = ((MonoObject *)str)->vtable->domain;
5470 ldstr_table = domain->ldstr_table;
5472 res = mono_g_hash_table_lookup (ldstr_table, str);
5478 /* Allocate outside the lock */
5480 s = mono_string_get_pinned (str);
5483 res = mono_g_hash_table_lookup (ldstr_table, str);
5488 mono_g_hash_table_insert (ldstr_table, s, s);
5493 LDStrInfo ldstr_info;
5494 ldstr_info.orig_domain = domain;
5495 ldstr_info.ins = str;
5496 ldstr_info.res = NULL;
5498 mono_domain_foreach (str_lookup, &ldstr_info);
5499 if (ldstr_info.res) {
5501 * the string was already interned in some other domain:
5502 * intern it in the current one as well.
5504 mono_g_hash_table_insert (ldstr_table, str, str);
5514 * mono_string_is_interned:
5515 * @o: String to probe
5517 * Returns whether the string has been interned.
5520 mono_string_is_interned (MonoString *o)
5522 MONO_REQ_GC_UNSAFE_MODE;
5524 return mono_string_is_interned_lookup (o, FALSE);
5528 * mono_string_intern:
5529 * @o: String to intern
5531 * Interns the string passed.
5532 * Returns: The interned string.
5535 mono_string_intern (MonoString *str)
5537 MONO_REQ_GC_UNSAFE_MODE;
5539 return mono_string_is_interned_lookup (str, TRUE);
5544 * @domain: the domain where the string will be used.
5545 * @image: a metadata context
5546 * @idx: index into the user string table.
5548 * Implementation for the ldstr opcode.
5549 * Returns: a loaded string from the @image/@idx combination.
5552 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
5554 MONO_REQ_GC_UNSAFE_MODE;
5556 if (image->dynamic) {
5557 MonoString *str = mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
5560 if (!mono_verifier_verify_string_signature (image, idx, NULL))
5561 return NULL; /*FIXME we should probably be raising an exception here*/
5562 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
5567 * mono_ldstr_metadata_sig
5568 * @domain: the domain for the string
5569 * @sig: the signature of a metadata string
5571 * Returns: a MonoString for a string stored in the metadata
5574 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
5576 MONO_REQ_GC_UNSAFE_MODE;
5578 const char *str = sig;
5579 MonoString *o, *interned;
5582 len2 = mono_metadata_decode_blob_size (str, &str);
5585 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
5586 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
5589 guint16 *p2 = (guint16*)mono_string_chars (o);
5590 for (i = 0; i < len2; ++i) {
5591 *p2 = GUINT16_FROM_LE (*p2);
5597 interned = mono_g_hash_table_lookup (domain->ldstr_table, o);
5600 return interned; /* o will get garbage collected */
5602 o = mono_string_get_pinned (o);
5605 interned = mono_g_hash_table_lookup (domain->ldstr_table, o);
5607 mono_g_hash_table_insert (domain->ldstr_table, o, o);
5617 * mono_string_to_utf8:
5618 * @s: a System.String
5620 * Returns the UTF8 representation for @s.
5621 * The resulting buffer needs to be freed with mono_free().
5623 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
5626 mono_string_to_utf8 (MonoString *s)
5628 MONO_REQ_GC_UNSAFE_MODE;
5631 char *result = mono_string_to_utf8_checked (s, &error);
5633 if (!mono_error_ok (&error))
5634 mono_error_raise_exception (&error);
5639 * mono_string_to_utf8_checked:
5640 * @s: a System.String
5641 * @error: a MonoError.
5643 * Converts a MonoString to its UTF8 representation. May fail; check
5644 * @error to determine whether the conversion was successful.
5645 * The resulting buffer should be freed with mono_free().
5648 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
5650 MONO_REQ_GC_UNSAFE_MODE;
5654 GError *gerror = NULL;
5656 mono_error_init (error);
5662 return g_strdup ("");
5664 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
5666 mono_error_set_argument (error, "string", "%s", gerror->message);
5667 g_error_free (gerror);
5670 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5671 if (s->length > written) {
5672 /* allocate the total length and copy the part of the string that has been converted */
5673 char *as2 = g_malloc0 (s->length);
5674 memcpy (as2, as, written);
5683 * mono_string_to_utf8_ignore:
5686 * Converts a MonoString to its UTF8 representation. Will ignore
5687 * invalid surrogate pairs.
5688 * The resulting buffer should be freed with mono_free().
5692 mono_string_to_utf8_ignore (MonoString *s)
5694 MONO_REQ_GC_UNSAFE_MODE;
5703 return g_strdup ("");
5705 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
5707 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5708 if (s->length > written) {
5709 /* allocate the total length and copy the part of the string that has been converted */
5710 char *as2 = g_malloc0 (s->length);
5711 memcpy (as2, as, written);
5720 * mono_string_to_utf8_image_ignore:
5721 * @s: a System.String
5723 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
5726 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
5728 MONO_REQ_GC_UNSAFE_MODE;
5730 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
5734 * mono_string_to_utf8_mp_ignore:
5735 * @s: a System.String
5737 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
5740 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
5742 MONO_REQ_GC_UNSAFE_MODE;
5744 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
5749 * mono_string_to_utf16:
5752 * Return an null-terminated array of the utf-16 chars
5753 * contained in @s. The result must be freed with g_free().
5754 * This is a temporary helper until our string implementation
5755 * is reworked to always include the null terminating char.
5758 mono_string_to_utf16 (MonoString *s)
5760 MONO_REQ_GC_UNSAFE_MODE;
5767 as = g_malloc ((s->length * 2) + 2);
5768 as [(s->length * 2)] = '\0';
5769 as [(s->length * 2) + 1] = '\0';
5772 return (gunichar2 *)(as);
5775 memcpy (as, mono_string_chars(s), s->length * 2);
5776 return (gunichar2 *)(as);
5780 * mono_string_to_utf32:
5783 * Return an null-terminated array of the UTF-32 (UCS-4) chars
5784 * contained in @s. The result must be freed with g_free().
5787 mono_string_to_utf32 (MonoString *s)
5789 MONO_REQ_GC_UNSAFE_MODE;
5791 mono_unichar4 *utf32_output = NULL;
5792 GError *error = NULL;
5793 glong items_written;
5798 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
5801 g_error_free (error);
5803 return utf32_output;
5807 * mono_string_from_utf16:
5808 * @data: the UTF16 string (LPWSTR) to convert
5810 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
5812 * Returns: a MonoString.
5815 mono_string_from_utf16 (gunichar2 *data)
5817 MONO_REQ_GC_UNSAFE_MODE;
5819 MonoDomain *domain = mono_domain_get ();
5825 while (data [len]) len++;
5827 return mono_string_new_utf16 (domain, data, len);
5831 * mono_string_from_utf32:
5832 * @data: the UTF32 string (LPWSTR) to convert
5834 * Converts a UTF32 (UCS-4)to a MonoString.
5836 * Returns: a MonoString.
5839 mono_string_from_utf32 (mono_unichar4 *data)
5841 MONO_REQ_GC_UNSAFE_MODE;
5843 MonoString* result = NULL;
5844 mono_unichar2 *utf16_output = NULL;
5845 GError *error = NULL;
5846 glong items_written;
5852 while (data [len]) len++;
5854 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &error);
5857 g_error_free (error);
5859 result = mono_string_from_utf16 (utf16_output);
5860 g_free (utf16_output);
5865 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
5867 MONO_REQ_GC_UNSAFE_MODE;
5874 r = mono_string_to_utf8_ignore (s);
5876 r = mono_string_to_utf8_checked (s, error);
5877 if (!mono_error_ok (error))
5884 len = strlen (r) + 1;
5886 mp_s = mono_mempool_alloc (mp, len);
5888 mp_s = mono_image_alloc (image, len);
5890 memcpy (mp_s, r, len);
5898 * mono_string_to_utf8_image:
5899 * @s: a System.String
5901 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
5904 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
5906 MONO_REQ_GC_UNSAFE_MODE;
5908 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
5912 * mono_string_to_utf8_mp:
5913 * @s: a System.String
5915 * Same as mono_string_to_utf8, but allocate the string from a mempool.
5918 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
5920 MONO_REQ_GC_UNSAFE_MODE;
5922 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
5926 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
5929 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
5931 eh_callbacks = *cbs;
5934 MonoRuntimeExceptionHandlingCallbacks *
5935 mono_get_eh_callbacks (void)
5937 return &eh_callbacks;
5941 * mono_raise_exception:
5942 * @ex: exception object
5944 * Signal the runtime that the exception @ex has been raised in unmanaged code.
5947 mono_raise_exception (MonoException *ex)
5949 MONO_REQ_GC_UNSAFE_MODE;
5952 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
5953 * that will cause gcc to omit the function epilog, causing problems when
5954 * the JIT tries to walk the stack, since the return address on the stack
5955 * will point into the next function in the executable, not this one.
5957 eh_callbacks.mono_raise_exception (ex);
5961 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
5963 MONO_REQ_GC_UNSAFE_MODE;
5965 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
5969 * mono_wait_handle_new:
5970 * @domain: Domain where the object will be created
5971 * @handle: Handle for the wait handle
5973 * Returns: A new MonoWaitHandle created in the given domain for the given handle
5976 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
5978 MONO_REQ_GC_UNSAFE_MODE;
5980 MonoWaitHandle *res;
5981 gpointer params [1];
5982 static MonoMethod *handle_set;
5984 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.manualresetevent_class);
5986 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
5988 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
5990 params [0] = &handle;
5991 mono_runtime_invoke (handle_set, res, params, NULL);
5997 mono_wait_handle_get_handle (MonoWaitHandle *handle)
5999 MONO_REQ_GC_UNSAFE_MODE;
6001 static MonoClassField *f_os_handle;
6002 static MonoClassField *f_safe_handle;
6004 if (!f_os_handle && !f_safe_handle) {
6005 f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
6006 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
6011 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
6015 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
6022 mono_runtime_capture_context (MonoDomain *domain)
6024 MONO_REQ_GC_UNSAFE_MODE;
6026 RuntimeInvokeFunction runtime_invoke;
6028 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
6029 MonoMethod *method = mono_get_context_capture_method ();
6030 MonoMethod *wrapper;
6033 wrapper = mono_marshal_get_runtime_invoke (method, FALSE, FALSE);
6034 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
6035 domain->capture_context_method = mono_compile_method (method);
6038 runtime_invoke = domain->capture_context_runtime_invoke;
6040 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
6043 * mono_async_result_new:
6044 * @domain:domain where the object will be created.
6045 * @handle: wait handle.
6046 * @state: state to pass to AsyncResult
6047 * @data: C closure data.
6049 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
6050 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
6054 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
6056 MONO_REQ_GC_UNSAFE_MODE;
6058 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
6059 MonoObject *context = mono_runtime_capture_context (domain);
6060 /* we must capture the execution context from the original thread */
6062 MONO_OBJECT_SETREF (res, execution_context, context);
6063 /* note: result may be null if the flow is suppressed */
6067 MONO_OBJECT_SETREF (res, object_data, object_data);
6068 MONO_OBJECT_SETREF (res, async_state, state);
6070 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
6072 res->sync_completed = FALSE;
6073 res->completed = FALSE;
6079 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
6081 MONO_REQ_GC_UNSAFE_MODE;
6087 g_assert (ares->async_delegate);
6089 ac = (MonoAsyncCall*) ares->object_data;
6091 res = mono_runtime_delegate_invoke (ares->async_delegate, (void**) &ares->async_state, NULL);
6093 gpointer wait_event = NULL;
6095 ac->msg->exc = NULL;
6096 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args);
6097 MONO_OBJECT_SETREF (ac, res, res);
6099 mono_monitor_enter ((MonoObject*) ares);
6100 ares->completed = 1;
6102 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
6103 mono_monitor_exit ((MonoObject*) ares);
6105 if (wait_event != NULL)
6106 SetEvent (wait_event);
6108 if (ac->cb_method) {
6109 /* we swallow the excepton as it is the behavior on .NET */
6110 MonoObject *exc = NULL;
6111 mono_runtime_invoke (ac->cb_method, ac->cb_target, (gpointer*) &ares, &exc);
6113 mono_unhandled_exception (exc);
6121 mono_message_init (MonoDomain *domain,
6122 MonoMethodMessage *this_obj,
6123 MonoReflectionMethod *method,
6124 MonoArray *out_args)
6126 MONO_REQ_GC_UNSAFE_MODE;
6128 static MonoClass *object_array_klass;
6129 static MonoClass *byte_array_klass;
6130 static MonoClass *string_array_klass;
6131 MonoMethodSignature *sig = mono_method_signature (method->method);
6137 if (!object_array_klass) {
6140 klass = mono_array_class_get (mono_defaults.byte_class, 1);
6142 byte_array_klass = klass;
6144 klass = mono_array_class_get (mono_defaults.string_class, 1);
6146 string_array_klass = klass;
6148 klass = mono_array_class_get (mono_defaults.object_class, 1);
6151 mono_atomic_store_release (&object_array_klass, klass);
6154 MONO_OBJECT_SETREF (this_obj, method, method);
6156 MONO_OBJECT_SETREF (this_obj, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
6157 MONO_OBJECT_SETREF (this_obj, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
6158 this_obj->async_result = NULL;
6159 this_obj->call_type = CallType_Sync;
6161 names = g_new (char *, sig->param_count);
6162 mono_method_get_param_names (method->method, (const char **) names);
6163 MONO_OBJECT_SETREF (this_obj, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
6165 for (i = 0; i < sig->param_count; i++) {
6166 name = mono_string_new (domain, names [i]);
6167 mono_array_setref (this_obj->names, i, name);
6171 for (i = 0, j = 0; i < sig->param_count; i++) {
6172 if (sig->params [i]->byref) {
6174 MonoObject* arg = mono_array_get (out_args, gpointer, j);
6175 mono_array_setref (this_obj->args, i, arg);
6179 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
6183 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
6186 mono_array_set (this_obj->arg_types, guint8, i, arg_type);
6190 #ifndef DISABLE_REMOTING
6192 * mono_remoting_invoke:
6193 * @real_proxy: pointer to a RealProxy object
6194 * @msg: The MonoMethodMessage to execute
6195 * @exc: used to store exceptions
6196 * @out_args: used to store output arguments
6198 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
6199 * IMessage interface and it is not trivial to extract results from there. So
6200 * we call an helper method PrivateInvoke instead of calling
6201 * RealProxy::Invoke() directly.
6203 * Returns: the result object.
6206 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
6207 MonoObject **exc, MonoArray **out_args)
6209 MONO_REQ_GC_UNSAFE_MODE;
6211 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
6214 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
6217 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
6219 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6220 real_proxy->vtable->domain->private_invoke_method = im;
6223 pa [0] = real_proxy;
6228 return mono_runtime_invoke (im, NULL, pa, exc);
6233 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
6234 MonoObject **exc, MonoArray **out_args)
6236 MONO_REQ_GC_UNSAFE_MODE;
6238 static MonoClass *object_array_klass;
6241 MonoMethodSignature *sig;
6243 int i, j, outarg_count = 0;
6245 #ifndef DISABLE_REMOTING
6246 if (target && mono_object_is_transparent_proxy (target)) {
6247 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
6248 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6249 target = tp->rp->unwrapped_server;
6251 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
6256 domain = mono_domain_get ();
6257 method = msg->method->method;
6258 sig = mono_method_signature (method);
6260 for (i = 0; i < sig->param_count; i++) {
6261 if (sig->params [i]->byref)
6265 if (!object_array_klass) {
6268 klass = mono_array_class_get (mono_defaults.object_class, 1);
6271 mono_memory_barrier ();
6272 object_array_klass = klass;
6275 mono_gc_wbarrier_generic_store (out_args, (MonoObject*) mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count));
6278 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
6280 for (i = 0, j = 0; i < sig->param_count; i++) {
6281 if (sig->params [i]->byref) {
6283 arg = mono_array_get (msg->args, gpointer, i);
6284 mono_array_setref (*out_args, j, arg);
6293 * mono_object_to_string:
6295 * @exc: Any exception thrown by ToString (). May be NULL.
6297 * Returns: the result of calling ToString () on an object.
6300 mono_object_to_string (MonoObject *obj, MonoObject **exc)
6302 MONO_REQ_GC_UNSAFE_MODE;
6304 static MonoMethod *to_string = NULL;
6311 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
6313 method = mono_object_get_virtual_method (obj, to_string);
6315 // Unbox value type if needed
6316 if (mono_class_is_valuetype (mono_method_get_class (method))) {
6317 target = mono_object_unbox (obj);
6320 return (MonoString *) mono_runtime_invoke (method, target, NULL, exc);
6324 * mono_print_unhandled_exception:
6325 * @exc: The exception
6327 * Prints the unhandled exception.
6330 mono_print_unhandled_exception (MonoObject *exc)
6332 MONO_REQ_GC_UNSAFE_MODE;
6335 char *message = (char*)"";
6336 gboolean free_message = FALSE;
6339 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
6340 message = g_strdup ("OutOfMemoryException");
6341 free_message = TRUE;
6342 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
6343 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
6344 free_message = TRUE;
6347 if (((MonoException*)exc)->native_trace_ips) {
6348 message = mono_exception_get_native_backtrace ((MonoException*)exc);
6349 free_message = TRUE;
6351 MonoObject *other_exc = NULL;
6352 str = mono_object_to_string (exc, &other_exc);
6354 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
6355 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
6357 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
6358 original_backtrace, nested_backtrace);
6360 g_free (original_backtrace);
6361 g_free (nested_backtrace);
6362 free_message = TRUE;
6364 message = mono_string_to_utf8_checked (str, &error);
6365 if (!mono_error_ok (&error)) {
6366 mono_error_cleanup (&error);
6367 message = (char *) "";
6369 free_message = TRUE;
6376 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
6377 * exc->vtable->klass->name, message);
6379 g_printerr ("\nUnhandled Exception:\n%s\n", message);
6386 * mono_delegate_ctor:
6387 * @this: pointer to an uninitialized delegate object
6388 * @target: target object
6389 * @addr: pointer to native code
6392 * Initialize a delegate and sets a specific method, not the one
6393 * associated with addr. This is useful when sharing generic code.
6394 * In that case addr will most probably not be associated with the
6395 * correct instantiation of the method.
6398 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method)
6400 MONO_REQ_GC_UNSAFE_MODE;
6402 MonoDelegate *delegate = (MonoDelegate *)this_obj;
6404 g_assert (this_obj);
6407 g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
6410 delegate->method = method;
6412 mono_stats.delegate_creations++;
6414 #ifndef DISABLE_REMOTING
6415 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
6417 method = mono_marshal_get_remoting_invoke (method);
6418 delegate->method_ptr = mono_compile_method (method);
6419 MONO_OBJECT_SETREF (delegate, target, target);
6423 delegate->method_ptr = addr;
6424 MONO_OBJECT_SETREF (delegate, target, target);
6427 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
6431 * mono_delegate_ctor:
6432 * @this: pointer to an uninitialized delegate object
6433 * @target: target object
6434 * @addr: pointer to native code
6436 * This is used to initialize a delegate.
6439 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr)
6441 MONO_REQ_GC_UNSAFE_MODE;
6443 MonoDomain *domain = mono_domain_get ();
6445 MonoMethod *method = NULL;
6449 ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr));
6451 if (!ji && domain != mono_get_root_domain ())
6452 ji = mono_jit_info_table_find (mono_get_root_domain (), mono_get_addr_from_ftnptr (addr));
6454 method = mono_jit_info_get_method (ji);
6455 g_assert (!method->klass->generic_container);
6458 mono_delegate_ctor_with_method (this_obj, target, addr, method);
6462 * mono_method_call_message_new:
6463 * @method: method to encapsulate
6464 * @params: parameters to the method
6465 * @invoke: optional, delegate invoke.
6466 * @cb: async callback delegate.
6467 * @state: state passed to the async callback.
6469 * Translates arguments pointers into a MonoMethodMessage.
6472 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
6473 MonoDelegate **cb, MonoObject **state)
6475 MONO_REQ_GC_UNSAFE_MODE;
6477 MonoDomain *domain = mono_domain_get ();
6478 MonoMethodSignature *sig = mono_method_signature (method);
6479 MonoMethodMessage *msg;
6482 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6485 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
6486 count = sig->param_count - 2;
6488 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
6489 count = sig->param_count;
6492 for (i = 0; i < count; i++) {
6497 if (sig->params [i]->byref)
6498 vpos = *((gpointer *)params [i]);
6502 class = mono_class_from_mono_type (sig->params [i]);
6504 if (class->valuetype)
6505 arg = mono_value_box (domain, class, vpos);
6507 arg = *((MonoObject **)vpos);
6509 mono_array_setref (msg->args, i, arg);
6512 if (cb != NULL && state != NULL) {
6513 *cb = *((MonoDelegate **)params [i]);
6515 *state = *((MonoObject **)params [i]);
6522 * mono_method_return_message_restore:
6524 * Restore results from message based processing back to arguments pointers
6527 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
6529 MONO_REQ_GC_UNSAFE_MODE;
6531 MonoMethodSignature *sig = mono_method_signature (method);
6532 int i, j, type, size, out_len;
6534 if (out_args == NULL)
6536 out_len = mono_array_length (out_args);
6540 for (i = 0, j = 0; i < sig->param_count; i++) {
6541 MonoType *pt = sig->params [i];
6546 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
6548 arg = mono_array_get (out_args, gpointer, j);
6551 g_assert (type != MONO_TYPE_VOID);
6553 if (MONO_TYPE_IS_REFERENCE (pt)) {
6554 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
6557 MonoClass *class = ((MonoObject*)arg)->vtable->klass;
6558 size = mono_class_value_size (class, NULL);
6559 if (class->has_references)
6560 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, class);
6562 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
6564 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
6565 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
6574 #ifndef DISABLE_REMOTING
6577 * mono_load_remote_field:
6578 * @this: pointer to an object
6579 * @klass: klass of the object containing @field
6580 * @field: the field to load
6581 * @res: a storage to store the result
6583 * This method is called by the runtime on attempts to load fields of
6584 * transparent proxy objects. @this points to such TP, @klass is the class of
6585 * the object containing @field. @res is a storage location which can be
6586 * used to store the result.
6588 * Returns: an address pointing to the value of field.
6591 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
6593 MONO_REQ_GC_UNSAFE_MODE;
6595 static MonoMethod *getter = NULL;
6596 MonoDomain *domain = mono_domain_get ();
6597 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
6598 MonoClass *field_class;
6599 MonoMethodMessage *msg;
6600 MonoArray *out_args;
6604 g_assert (mono_object_is_transparent_proxy (this_obj));
6605 g_assert (res != NULL);
6607 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6608 mono_field_get_value (tp->rp->unwrapped_server, field, res);
6613 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6615 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6618 field_class = mono_class_from_mono_type (field->type);
6620 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6621 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6622 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6624 full_name = mono_type_get_full_name (klass);
6625 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6626 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6629 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6631 if (exc) mono_raise_exception ((MonoException *)exc);
6633 if (mono_array_length (out_args) == 0)
6636 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
6638 if (field_class->valuetype) {
6639 return ((char *)*res) + sizeof (MonoObject);
6645 * mono_load_remote_field_new:
6650 * Missing documentation.
6653 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
6655 MONO_REQ_GC_UNSAFE_MODE;
6657 static MonoMethod *getter = NULL;
6658 MonoDomain *domain = mono_domain_get ();
6659 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
6660 MonoClass *field_class;
6661 MonoMethodMessage *msg;
6662 MonoArray *out_args;
6663 MonoObject *exc, *res;
6666 g_assert (mono_object_is_transparent_proxy (this_obj));
6668 field_class = mono_class_from_mono_type (field->type);
6670 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6672 if (field_class->valuetype) {
6673 res = mono_object_new (domain, field_class);
6674 val = ((gchar *) res) + sizeof (MonoObject);
6678 mono_field_get_value (tp->rp->unwrapped_server, field, val);
6683 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6685 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6688 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6689 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6691 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6693 full_name = mono_type_get_full_name (klass);
6694 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6695 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6698 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6700 if (exc) mono_raise_exception ((MonoException *)exc);
6702 if (mono_array_length (out_args) == 0)
6705 res = mono_array_get (out_args, MonoObject *, 0);
6711 * mono_store_remote_field:
6712 * @this_obj: pointer to an object
6713 * @klass: klass of the object containing @field
6714 * @field: the field to load
6715 * @val: the value/object to store
6717 * This method is called by the runtime on attempts to store fields of
6718 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
6719 * the object containing @field. @val is the new value to store in @field.
6722 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
6724 MONO_REQ_GC_UNSAFE_MODE;
6726 static MonoMethod *setter = NULL;
6727 MonoDomain *domain = mono_domain_get ();
6728 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
6729 MonoClass *field_class;
6730 MonoMethodMessage *msg;
6731 MonoArray *out_args;
6736 g_assert (mono_object_is_transparent_proxy (this_obj));
6738 field_class = mono_class_from_mono_type (field->type);
6740 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6741 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
6742 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
6747 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6749 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6752 if (field_class->valuetype)
6753 arg = mono_value_box (domain, field_class, val);
6755 arg = *((MonoObject **)val);
6758 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6759 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6761 full_name = mono_type_get_full_name (klass);
6762 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6763 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6764 mono_array_setref (msg->args, 2, arg);
6767 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6769 if (exc) mono_raise_exception ((MonoException *)exc);
6773 * mono_store_remote_field_new:
6779 * Missing documentation
6782 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
6784 MONO_REQ_GC_UNSAFE_MODE;
6786 static MonoMethod *setter = NULL;
6787 MonoDomain *domain = mono_domain_get ();
6788 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
6789 MonoClass *field_class;
6790 MonoMethodMessage *msg;
6791 MonoArray *out_args;
6795 g_assert (mono_object_is_transparent_proxy (this_obj));
6797 field_class = mono_class_from_mono_type (field->type);
6799 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6800 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
6801 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
6806 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6808 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6811 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6812 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6814 full_name = mono_type_get_full_name (klass);
6815 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6816 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6817 mono_array_setref (msg->args, 2, arg);
6820 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6822 if (exc) mono_raise_exception ((MonoException *)exc);
6827 * mono_create_ftnptr:
6829 * Given a function address, create a function descriptor for it.
6830 * This is only needed on some platforms.
6833 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
6835 return callbacks.create_ftnptr (domain, addr);
6839 * mono_get_addr_from_ftnptr:
6841 * Given a pointer to a function descriptor, return the function address.
6842 * This is only needed on some platforms.
6845 mono_get_addr_from_ftnptr (gpointer descr)
6847 return callbacks.get_addr_from_ftnptr (descr);
6851 * mono_string_chars:
6854 * Returns a pointer to the UCS16 characters stored in the MonoString
6857 mono_string_chars (MonoString *s)
6859 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
6865 * mono_string_length:
6868 * Returns the lenght in characters of the string
6871 mono_string_length (MonoString *s)
6873 MONO_REQ_GC_UNSAFE_MODE;
6879 * mono_array_length:
6880 * @array: a MonoArray*
6882 * Returns the total number of elements in the array. This works for
6883 * both vectors and multidimensional arrays.
6886 mono_array_length (MonoArray *array)
6888 MONO_REQ_GC_UNSAFE_MODE;
6890 return array->max_length;
6894 * mono_array_addr_with_size:
6895 * @array: a MonoArray*
6896 * @size: size of the array elements
6897 * @idx: index into the array
6899 * Returns the address of the @idx element in the array.
6902 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
6904 MONO_REQ_GC_UNSAFE_MODE;
6906 return ((char*)(array)->vector) + size * idx;
6911 mono_glist_to_array (GList *list, MonoClass *eclass)
6913 MonoDomain *domain = mono_domain_get ();
6920 len = g_list_length (list);
6921 res = mono_array_new (domain, eclass, len);
6923 for (i = 0; list; list = list->next, i++)
6924 mono_array_set (res, gpointer, i, list->data);