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/threadpool.h>
31 #include <mono/metadata/marshal.h>
32 #include "mono/metadata/debug-helpers.h"
33 #include "mono/metadata/marshal.h"
34 #include <mono/metadata/threads.h>
35 #include <mono/metadata/threads-types.h>
36 #include <mono/metadata/environment.h>
37 #include "mono/metadata/profiler-private.h"
38 #include "mono/metadata/security-manager.h"
39 #include "mono/metadata/mono-debug-debugger.h"
40 #include <mono/metadata/gc-internal.h>
41 #include <mono/metadata/verify-internals.h>
42 #include <mono/utils/strenc.h>
43 #include <mono/utils/mono-counters.h>
44 #include <mono/utils/mono-error-internals.h>
45 #include <mono/utils/mono-memory-model.h>
46 #include "cominterop.h"
48 #if defined(HAVE_BOEHM_GC)
49 #define GC_NO_DESCRIPTOR ((gpointer)(0 | GC_DS_LENGTH))
50 #elif defined(HAVE_SGEN_GC)
51 #define GC_NO_DESCRIPTOR (NULL)
53 #define GC_NO_DESCRIPTOR (NULL)
57 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value);
60 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig);
63 free_main_args (void);
66 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error);
69 #define ldstr_lock() mono_mutex_lock (&ldstr_section)
70 #define ldstr_unlock() mono_mutex_unlock (&ldstr_section)
71 static mono_mutex_t ldstr_section;
74 mono_runtime_object_init (MonoObject *this)
76 MonoMethod *method = NULL;
77 MonoClass *klass = this->vtable->klass;
79 method = mono_class_get_method_from_name (klass, ".ctor", 0);
81 g_error ("Could not lookup zero argument constructor for class %s", mono_type_get_full_name (klass));
83 if (method->klass->valuetype)
84 this = mono_object_unbox (this);
85 mono_runtime_invoke (method, this, NULL, NULL);
88 /* The pseudo algorithm for type initialization from the spec
89 Note it doesn't say anything about domains - only threads.
91 2. If the type is initialized you are done.
92 2.1. If the type is not yet initialized, try to take an
94 2.2. If successful, record this thread as responsible for
95 initializing the type and proceed to step 2.3.
96 2.2.1. If not, see whether this thread or any thread
97 waiting for this thread to complete already holds the lock.
98 2.2.2. If so, return since blocking would create a deadlock. This thread
99 will now see an incompletely initialized state for the type,
100 but no deadlock will arise.
101 2.2.3 If not, block until the type is initialized then return.
102 2.3 Initialize the parent type and then all interfaces implemented
104 2.4 Execute the type initialization code for this type.
105 2.5 Mark the type as initialized, release the initialization lock,
106 awaken any threads waiting for this type to be initialized,
113 guint32 initializing_tid;
114 guint32 waiting_count;
116 mono_mutex_t initialization_section;
117 } TypeInitializationLock;
119 /* for locking access to type_initialization_hash and blocked_thread_hash */
120 #define mono_type_initialization_lock() mono_mutex_lock (&type_initialization_section)
121 #define mono_type_initialization_unlock() mono_mutex_unlock (&type_initialization_section)
122 static mono_mutex_t type_initialization_section;
126 mono_type_init_lock (TypeInitializationLock *lock)
129 mono_mutex_lock (&lock->initialization_section);
130 MONO_FINISH_TRY_BLOCKING
134 mono_type_init_unlock (TypeInitializationLock *lock)
136 mono_mutex_unlock (&lock->initialization_section);
139 /* from vtable to lock */
140 static GHashTable *type_initialization_hash;
142 /* from thread id to thread id being waited on */
143 static GHashTable *blocked_thread_hash;
146 static MonoThread *main_thread;
148 /* Functions supplied by the runtime */
149 static MonoRuntimeCallbacks callbacks;
152 * mono_thread_set_main:
153 * @thread: thread to set as the main thread
155 * This function can be used to instruct the runtime to treat @thread
156 * as the main thread, ie, the thread that would normally execute the Main()
157 * method. This basically means that at the end of @thread, the runtime will
158 * wait for the existing foreground threads to quit and other such details.
161 mono_thread_set_main (MonoThread *thread)
163 static gboolean registered = FALSE;
166 MONO_GC_REGISTER_ROOT_SINGLE (main_thread);
170 main_thread = thread;
174 mono_thread_get_main (void)
180 mono_type_initialization_init (void)
182 mono_mutex_init_recursive (&type_initialization_section);
183 type_initialization_hash = g_hash_table_new (NULL, NULL);
184 blocked_thread_hash = g_hash_table_new (NULL, NULL);
185 mono_mutex_init_recursive (&ldstr_section);
189 mono_type_initialization_cleanup (void)
192 /* This is causing race conditions with
193 * mono_release_type_locks
195 mono_mutex_destroy (&type_initialization_section);
196 g_hash_table_destroy (type_initialization_hash);
197 type_initialization_hash = NULL;
199 mono_mutex_destroy (&ldstr_section);
200 g_hash_table_destroy (blocked_thread_hash);
201 blocked_thread_hash = NULL;
207 * get_type_init_exception_for_vtable:
209 * Return the stored type initialization exception for VTABLE.
211 static MonoException*
212 get_type_init_exception_for_vtable (MonoVTable *vtable)
214 MonoDomain *domain = vtable->domain;
215 MonoClass *klass = vtable->klass;
219 if (!vtable->init_failed)
220 g_error ("Trying to get the init exception for a non-failed vtable of class %s", mono_type_get_full_name (klass));
223 * If the initializing thread was rudely aborted, the exception is not stored
227 mono_domain_lock (domain);
228 if (domain->type_init_exception_hash)
229 ex = mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
230 mono_domain_unlock (domain);
233 if (klass->name_space && *klass->name_space)
234 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
236 full_name = g_strdup (klass->name);
237 ex = mono_get_exception_type_initialization (full_name, NULL);
244 * mono_runtime_class_init:
245 * @vtable: vtable that needs to be initialized
247 * This routine calls the class constructor for @vtable.
250 mono_runtime_class_init (MonoVTable *vtable)
252 mono_runtime_class_init_full (vtable, TRUE);
256 * mono_runtime_class_init_full:
257 * @vtable that neeeds to be initialized
258 * @raise_exception is TRUE, exceptions are raised intead of returned
262 mono_runtime_class_init_full (MonoVTable *vtable, gboolean raise_exception)
265 MonoException *exc_to_throw;
266 MonoMethod *method = NULL;
270 if (vtable->initialized)
274 klass = vtable->klass;
276 if (!klass->image->checked_module_cctor) {
277 mono_image_check_for_module_cctor (klass->image);
278 if (klass->image->has_module_cctor) {
280 MonoClass *module_klass;
281 MonoVTable *module_vtable;
283 module_klass = mono_class_get_checked (klass->image, MONO_TOKEN_TYPE_DEF | 1, &error);
285 exc = mono_error_convert_to_exception (&error);
287 mono_raise_exception (exc);
291 module_vtable = mono_class_vtable_full (vtable->domain, module_klass, raise_exception);
294 exc = mono_runtime_class_init_full (module_vtable, raise_exception);
299 method = mono_class_get_cctor (klass);
302 MonoDomain *domain = vtable->domain;
303 TypeInitializationLock *lock;
304 guint32 tid = GetCurrentThreadId();
305 int do_initialization = 0;
306 MonoDomain *last_domain = NULL;
308 mono_type_initialization_lock ();
309 /* double check... */
310 if (vtable->initialized) {
311 mono_type_initialization_unlock ();
314 if (vtable->init_failed) {
315 mono_type_initialization_unlock ();
317 /* The type initialization already failed once, rethrow the same exception */
319 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
320 return get_type_init_exception_for_vtable (vtable);
322 lock = g_hash_table_lookup (type_initialization_hash, vtable);
324 /* This thread will get to do the initialization */
325 if (mono_domain_get () != domain) {
326 /* Transfer into the target domain */
327 last_domain = mono_domain_get ();
328 if (!mono_domain_set (domain, FALSE)) {
329 vtable->initialized = 1;
330 mono_type_initialization_unlock ();
332 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
333 return mono_get_exception_appdomain_unloaded ();
336 lock = g_malloc (sizeof(TypeInitializationLock));
337 mono_mutex_init_recursive (&lock->initialization_section);
338 lock->initializing_tid = tid;
339 lock->waiting_count = 1;
341 /* grab the vtable lock while this thread still owns type_initialization_section */
342 mono_type_init_lock (lock);
343 g_hash_table_insert (type_initialization_hash, vtable, lock);
344 do_initialization = 1;
347 TypeInitializationLock *pending_lock;
349 if (lock->initializing_tid == tid || lock->done) {
350 mono_type_initialization_unlock ();
353 /* see if the thread doing the initialization is already blocked on this thread */
354 blocked = GUINT_TO_POINTER (lock->initializing_tid);
355 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
356 if (pending_lock->initializing_tid == tid) {
357 if (!pending_lock->done) {
358 mono_type_initialization_unlock ();
361 /* the thread doing the initialization is blocked on this thread,
362 but on a lock that has already been freed. It just hasn't got
367 blocked = GUINT_TO_POINTER (pending_lock->initializing_tid);
369 ++lock->waiting_count;
370 /* record the fact that we are waiting on the initializing thread */
371 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
373 mono_type_initialization_unlock ();
375 if (do_initialization) {
376 mono_runtime_invoke (method, NULL, NULL, (MonoObject **) &exc);
378 /* If the initialization failed, mark the class as unusable. */
379 /* Avoid infinite loops */
381 (klass->image == mono_defaults.corlib &&
382 !strcmp (klass->name_space, "System") &&
383 !strcmp (klass->name, "TypeInitializationException")))) {
384 vtable->init_failed = 1;
386 if (klass->name_space && *klass->name_space)
387 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
389 full_name = g_strdup (klass->name);
390 exc_to_throw = mono_get_exception_type_initialization (full_name, exc);
394 * Store the exception object so it could be thrown on subsequent
397 mono_domain_lock (domain);
398 if (!domain->type_init_exception_hash)
399 domain->type_init_exception_hash = mono_g_hash_table_new_type (mono_aligned_addr_hash, NULL, MONO_HASH_VALUE_GC);
400 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
401 mono_domain_unlock (domain);
405 mono_domain_set (last_domain, TRUE);
407 mono_type_init_unlock (lock);
409 /* this just blocks until the initializing thread is done */
410 mono_type_init_lock (lock);
411 mono_type_init_unlock (lock);
414 mono_type_initialization_lock ();
415 if (lock->initializing_tid != tid)
416 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
417 --lock->waiting_count;
418 if (lock->waiting_count == 0) {
419 mono_mutex_destroy (&lock->initialization_section);
420 g_hash_table_remove (type_initialization_hash, vtable);
423 mono_memory_barrier ();
424 if (!vtable->init_failed)
425 vtable->initialized = 1;
426 mono_type_initialization_unlock ();
428 if (vtable->init_failed) {
429 /* Either we were the initializing thread or we waited for the initialization */
431 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
432 return get_type_init_exception_for_vtable (vtable);
435 vtable->initialized = 1;
442 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
444 MonoVTable *vtable = (MonoVTable*)key;
446 TypeInitializationLock *lock = (TypeInitializationLock*) value;
447 if (lock->initializing_tid == GPOINTER_TO_UINT (user) && !lock->done) {
450 * Have to set this since it cannot be set by the normal code in
451 * mono_runtime_class_init (). In this case, the exception object is not stored,
452 * and get_type_init_exception_for_class () needs to be aware of this.
454 vtable->init_failed = 1;
455 mono_type_init_unlock (lock);
456 --lock->waiting_count;
457 if (lock->waiting_count == 0) {
458 mono_mutex_destroy (&lock->initialization_section);
467 mono_release_type_locks (MonoInternalThread *thread)
469 mono_type_initialization_lock ();
470 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, (gpointer)(gsize)(thread->tid));
471 mono_type_initialization_unlock ();
475 default_trampoline (MonoMethod *method)
481 default_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
483 g_assert_not_reached ();
488 #ifndef DISABLE_REMOTING
491 default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target)
493 g_error ("remoting not installed");
497 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
501 default_delegate_trampoline (MonoDomain *domain, MonoClass *klass)
503 g_assert_not_reached ();
507 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
508 static MonoJumpTrampoline arch_create_jump_trampoline = default_jump_trampoline;
509 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
510 static MonoImtThunkBuilder imt_thunk_builder;
511 #if (MONO_IMT_SIZE > 32)
512 #error "MONO_IMT_SIZE cannot be larger than 32"
516 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
518 memcpy (&callbacks, cbs, sizeof (*cbs));
521 MonoRuntimeCallbacks*
522 mono_get_runtime_callbacks (void)
528 mono_install_trampoline (MonoTrampoline func)
530 arch_create_jit_trampoline = func? func: default_trampoline;
534 mono_install_jump_trampoline (MonoJumpTrampoline func)
536 arch_create_jump_trampoline = func? func: default_jump_trampoline;
539 #ifndef DISABLE_REMOTING
541 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
543 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
548 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
550 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
554 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
555 imt_thunk_builder = func;
558 static MonoCompileFunc default_mono_compile_method = NULL;
561 * mono_install_compile_method:
562 * @func: function to install
564 * This is a VM internal routine
567 mono_install_compile_method (MonoCompileFunc func)
569 default_mono_compile_method = func;
573 * mono_compile_method:
574 * @method: The method to compile.
576 * This JIT-compiles the method, and returns the pointer to the native code
580 mono_compile_method (MonoMethod *method)
582 if (!default_mono_compile_method) {
583 g_error ("compile method called on uninitialized runtime");
586 return default_mono_compile_method (method);
590 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
592 return arch_create_jump_trampoline (domain, method, add_sync_wrapper);
596 mono_runtime_create_delegate_trampoline (MonoClass *klass)
598 return arch_create_delegate_trampoline (mono_domain_get (), klass);
601 static MonoFreeMethodFunc default_mono_free_method = NULL;
604 * mono_install_free_method:
605 * @func: pointer to the MonoFreeMethodFunc used to release a method
607 * This is an internal VM routine, it is used for the engines to
608 * register a handler to release the resources associated with a method.
610 * Methods are freed when no more references to the delegate that holds
614 mono_install_free_method (MonoFreeMethodFunc func)
616 default_mono_free_method = func;
620 * mono_runtime_free_method:
621 * @domain; domain where the method is hosted
622 * @method: method to release
624 * This routine is invoked to free the resources associated with
625 * a method that has been JIT compiled. This is used to discard
626 * methods that were used only temporarily (for example, used in marshalling)
630 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
632 if (default_mono_free_method != NULL)
633 default_mono_free_method (domain, method);
635 mono_method_clear_object (domain, method);
637 mono_free_method (method);
641 * The vtables in the root appdomain are assumed to be reachable by other
642 * roots, and we don't use typed allocation in the other domains.
645 /* The sync block is no longer a GC pointer */
646 #define GC_HEADER_BITMAP (0)
648 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
651 compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
653 MonoClassField *field;
659 max_size = mono_class_data_size (class) / sizeof (gpointer);
661 max_size = class->instance_size / sizeof (gpointer);
662 if (max_size > size) {
663 g_assert (offset <= 0);
664 bitmap = g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
669 /*An Ephemeron cannot be marked by sgen*/
670 if (!static_fields && class->image == mono_defaults.corlib && !strcmp ("Ephemeron", class->name)) {
672 memset (bitmap, 0, size / 8);
677 for (p = class; p != NULL; p = p->parent) {
678 gpointer iter = NULL;
679 while ((field = mono_class_get_fields (p, &iter))) {
683 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
685 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
688 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
691 /* FIXME: should not happen, flag as type load error */
692 if (field->type->byref)
695 if (static_fields && field->offset == -1)
699 pos = field->offset / sizeof (gpointer);
702 type = mono_type_get_underlying_type (field->type);
703 switch (type->type) {
706 case MONO_TYPE_FNPTR:
708 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
713 if (class->image != mono_defaults.corlib)
716 case MONO_TYPE_STRING:
717 case MONO_TYPE_SZARRAY:
718 case MONO_TYPE_CLASS:
719 case MONO_TYPE_OBJECT:
720 case MONO_TYPE_ARRAY:
721 g_assert ((field->offset % sizeof(gpointer)) == 0);
723 g_assert (pos < size || pos <= max_size);
724 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
725 *max_set = MAX (*max_set, pos);
727 case MONO_TYPE_GENERICINST:
728 if (!mono_type_generic_inst_is_valuetype (type)) {
729 g_assert ((field->offset % sizeof(gpointer)) == 0);
731 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
732 *max_set = MAX (*max_set, pos);
737 case MONO_TYPE_VALUETYPE: {
738 MonoClass *fclass = mono_class_from_mono_type (field->type);
739 if (fclass->has_references) {
740 /* remove the object header */
741 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
755 case MONO_TYPE_BOOLEAN:
759 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
770 * mono_class_compute_bitmap:
772 * Mono internal function to compute a bitmap of reference fields in a class.
775 mono_class_compute_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
777 return compute_class_bitmap (class, bitmap, size, offset, max_set, static_fields);
782 * similar to the above, but sets the bits in the bitmap for any non-ref field
783 * and ignores static fields
786 compute_class_non_ref_bitmap (MonoClass *class, gsize *bitmap, int size, int offset)
788 MonoClassField *field;
793 max_size = class->instance_size / sizeof (gpointer);
794 if (max_size >= size) {
795 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
798 for (p = class; p != NULL; p = p->parent) {
799 gpointer iter = NULL;
800 while ((field = mono_class_get_fields (p, &iter))) {
803 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
805 /* FIXME: should not happen, flag as type load error */
806 if (field->type->byref)
809 pos = field->offset / sizeof (gpointer);
812 type = mono_type_get_underlying_type (field->type);
813 switch (type->type) {
814 #if SIZEOF_VOID_P == 8
818 case MONO_TYPE_FNPTR:
823 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
824 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
825 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
828 #if SIZEOF_VOID_P == 4
832 case MONO_TYPE_FNPTR:
837 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
838 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
839 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
845 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
846 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
847 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
850 case MONO_TYPE_BOOLEAN:
853 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
855 case MONO_TYPE_STRING:
856 case MONO_TYPE_SZARRAY:
857 case MONO_TYPE_CLASS:
858 case MONO_TYPE_OBJECT:
859 case MONO_TYPE_ARRAY:
861 case MONO_TYPE_GENERICINST:
862 if (!mono_type_generic_inst_is_valuetype (type)) {
867 case MONO_TYPE_VALUETYPE: {
868 MonoClass *fclass = mono_class_from_mono_type (field->type);
869 /* remove the object header */
870 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
874 g_assert_not_reached ();
883 * mono_class_insecure_overlapping:
884 * check if a class with explicit layout has references and non-references
885 * fields overlapping.
887 * Returns: TRUE if it is insecure to load the type.
890 mono_class_insecure_overlapping (MonoClass *klass)
894 gsize default_bitmap [4] = {0};
896 gsize default_nrbitmap [4] = {0};
897 int i, insecure = FALSE;
900 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
901 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
903 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
904 int idx = i % (sizeof (bitmap [0]) * 8);
905 if (bitmap [idx] & nrbitmap [idx]) {
910 if (bitmap != default_bitmap)
912 if (nrbitmap != default_nrbitmap)
915 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
923 mono_string_alloc (int length)
925 return mono_string_new_size (mono_domain_get (), length);
929 mono_class_compute_gc_descriptor (MonoClass *class)
933 gsize default_bitmap [4] = {0};
934 static gboolean gcj_inited = FALSE;
939 mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
940 mono_register_jit_icall (mono_string_alloc, "mono_string_alloc", mono_create_icall_signature ("object int"), FALSE);
943 mono_loader_unlock ();
947 mono_class_init (class);
949 if (class->gc_descr_inited)
952 class->gc_descr_inited = TRUE;
953 class->gc_descr = GC_NO_DESCRIPTOR;
955 bitmap = default_bitmap;
956 if (class == mono_defaults.string_class) {
957 class->gc_descr = (gpointer)mono_gc_make_descr_for_string (bitmap, 2);
958 } else if (class->rank) {
959 mono_class_compute_gc_descriptor (class->element_class);
960 if (MONO_TYPE_IS_REFERENCE (&class->element_class->byval_arg)) {
962 class->gc_descr = mono_gc_make_descr_for_array (class->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
963 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
964 class->name_space, class->name);*/
966 /* remove the object header */
967 bitmap = compute_class_bitmap (class->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
968 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));
969 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
970 class->name_space, class->name);*/
971 if (bitmap != default_bitmap)
975 /*static int count = 0;
978 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
979 class->gc_descr = (gpointer)mono_gc_make_descr_for_object (bitmap, max_set + 1, class->instance_size);
981 if (class->gc_descr == GC_NO_DESCRIPTOR)
982 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
984 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
985 if (bitmap != default_bitmap)
991 * field_is_special_static:
992 * @fklass: The MonoClass to look up.
993 * @field: The MonoClassField describing the field.
995 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
996 * SPECIAL_STATIC_NONE otherwise.
999 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1001 MonoCustomAttrInfo *ainfo;
1003 ainfo = mono_custom_attrs_from_field (fklass, field);
1006 for (i = 0; i < ainfo->num_attrs; ++i) {
1007 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1008 if (klass->image == mono_defaults.corlib) {
1009 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1010 mono_custom_attrs_free (ainfo);
1011 return SPECIAL_STATIC_THREAD;
1013 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1014 mono_custom_attrs_free (ainfo);
1015 return SPECIAL_STATIC_CONTEXT;
1019 mono_custom_attrs_free (ainfo);
1020 return SPECIAL_STATIC_NONE;
1023 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1024 #define mix(a,b,c) { \
1025 a -= c; a ^= rot(c, 4); c += b; \
1026 b -= a; b ^= rot(a, 6); a += c; \
1027 c -= b; c ^= rot(b, 8); b += a; \
1028 a -= c; a ^= rot(c,16); c += b; \
1029 b -= a; b ^= rot(a,19); a += c; \
1030 c -= b; c ^= rot(b, 4); b += a; \
1032 #define final(a,b,c) { \
1033 c ^= b; c -= rot(b,14); \
1034 a ^= c; a -= rot(c,11); \
1035 b ^= a; b -= rot(a,25); \
1036 c ^= b; c -= rot(b,16); \
1037 a ^= c; a -= rot(c,4); \
1038 b ^= a; b -= rot(a,14); \
1039 c ^= b; c -= rot(b,24); \
1043 * mono_method_get_imt_slot:
1045 * The IMT slot is embedded into AOTed code, so this must return the same value
1046 * for the same method across all executions. This means:
1047 * - pointers shouldn't be used as hash values.
1048 * - mono_metadata_str_hash () should be used for hashing strings.
1051 mono_method_get_imt_slot (MonoMethod *method)
1053 MonoMethodSignature *sig;
1055 guint32 *hashes_start, *hashes;
1059 /* This can be used to stress tests the collision code */
1063 * We do this to simplify generic sharing. It will hurt
1064 * performance in cases where a class implements two different
1065 * instantiations of the same generic interface.
1066 * The code in build_imt_slots () depends on this.
1068 if (method->is_inflated)
1069 method = ((MonoMethodInflated*)method)->declaring;
1071 sig = mono_method_signature (method);
1072 hashes_count = sig->param_count + 4;
1073 hashes_start = malloc (hashes_count * sizeof (guint32));
1074 hashes = hashes_start;
1076 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1077 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1078 method->klass->name_space, method->klass->name, method->name);
1081 /* Initialize hashes */
1082 hashes [0] = mono_metadata_str_hash (method->klass->name);
1083 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1084 hashes [2] = mono_metadata_str_hash (method->name);
1085 hashes [3] = mono_metadata_type_hash (sig->ret);
1086 for (i = 0; i < sig->param_count; i++) {
1087 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1090 /* Setup internal state */
1091 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1093 /* Handle most of the hashes */
1094 while (hashes_count > 3) {
1103 /* Handle the last 3 hashes (all the case statements fall through) */
1104 switch (hashes_count) {
1105 case 3 : c += hashes [2];
1106 case 2 : b += hashes [1];
1107 case 1 : a += hashes [0];
1109 case 0: /* nothing left to add */
1113 free (hashes_start);
1114 /* Report the result */
1115 return c % MONO_IMT_SIZE;
1124 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1125 guint32 imt_slot = mono_method_get_imt_slot (method);
1126 MonoImtBuilderEntry *entry;
1128 if (slot_num >= 0 && imt_slot != slot_num) {
1129 /* we build just a single imt slot and this is not it */
1133 entry = g_malloc0 (sizeof (MonoImtBuilderEntry));
1134 entry->key = method;
1135 entry->value.vtable_slot = vtable_slot;
1136 entry->next = imt_builder [imt_slot];
1137 if (imt_builder [imt_slot] != NULL) {
1138 entry->children = imt_builder [imt_slot]->children + 1;
1139 if (entry->children == 1) {
1140 mono_stats.imt_slots_with_collisions++;
1141 *imt_collisions_bitmap |= (1 << imt_slot);
1144 entry->children = 0;
1145 mono_stats.imt_used_slots++;
1147 imt_builder [imt_slot] = entry;
1150 char *method_name = mono_method_full_name (method, TRUE);
1151 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1152 method, method_name, imt_slot, vtable_slot, entry->children);
1153 g_free (method_name);
1160 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1162 MonoMethod *method = e->key;
1163 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1167 method->klass->name_space,
1168 method->klass->name,
1171 printf (" * %s: NULL\n", message);
1177 compare_imt_builder_entries (const void *p1, const void *p2) {
1178 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1179 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1181 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1185 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1187 int count = end - start;
1188 int chunk_start = out_array->len;
1191 for (i = start; i < end; ++i) {
1192 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1193 item->key = sorted_array [i]->key;
1194 item->value = sorted_array [i]->value;
1195 item->has_target_code = sorted_array [i]->has_target_code;
1196 item->is_equals = TRUE;
1198 item->check_target_idx = out_array->len + 1;
1200 item->check_target_idx = 0;
1201 g_ptr_array_add (out_array, item);
1204 int middle = start + count / 2;
1205 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1207 item->key = sorted_array [middle]->key;
1208 item->is_equals = FALSE;
1209 g_ptr_array_add (out_array, item);
1210 imt_emit_ir (sorted_array, start, middle, out_array);
1211 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1217 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1218 int number_of_entries = entries->children + 1;
1219 MonoImtBuilderEntry **sorted_array = malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1220 GPtrArray *result = g_ptr_array_new ();
1221 MonoImtBuilderEntry *current_entry;
1224 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1225 sorted_array [i] = current_entry;
1227 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1229 /*for (i = 0; i < number_of_entries; i++) {
1230 print_imt_entry (" sorted array:", sorted_array [i], i);
1233 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1235 free (sorted_array);
1240 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1242 if (imt_builder_entry != NULL) {
1243 if (imt_builder_entry->children == 0 && !fail_tramp) {
1244 /* No collision, return the vtable slot contents */
1245 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1247 /* Collision, build the thunk */
1248 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1251 result = imt_thunk_builder (vtable, domain,
1252 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1253 for (i = 0; i < imt_ir->len; ++i)
1254 g_free (g_ptr_array_index (imt_ir, i));
1255 g_ptr_array_free (imt_ir, TRUE);
1267 static MonoImtBuilderEntry*
1268 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1271 * LOCKING: requires the loader and domain locks.
1275 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1279 guint32 imt_collisions_bitmap = 0;
1280 MonoImtBuilderEntry **imt_builder = calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1281 int method_count = 0;
1282 gboolean record_method_count_for_max_collisions = FALSE;
1283 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1286 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1288 for (i = 0; i < klass->interface_offsets_count; ++i) {
1289 MonoClass *iface = klass->interfaces_packed [i];
1290 int interface_offset = klass->interface_offsets_packed [i];
1291 int method_slot_in_interface, vt_slot;
1293 if (mono_class_has_variant_generic_params (iface))
1294 has_variant_iface = TRUE;
1296 mono_class_setup_methods (iface);
1297 vt_slot = interface_offset;
1298 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1301 if (slot_num >= 0 && iface->is_inflated) {
1303 * The imt slot of the method is the same as for its declaring method,
1304 * see the comment in mono_method_get_imt_slot (), so we can
1305 * avoid inflating methods which will be discarded by
1306 * add_imt_builder_entry anyway.
1308 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1309 if (mono_method_get_imt_slot (method) != slot_num) {
1314 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1315 if (method->is_generic) {
1316 has_generic_virtual = TRUE;
1321 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1322 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1327 if (extra_interfaces) {
1328 int interface_offset = klass->vtable_size;
1330 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1331 MonoClass* iface = list_item->data;
1332 int method_slot_in_interface;
1333 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1334 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1336 if (method->is_generic)
1337 has_generic_virtual = TRUE;
1338 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1340 interface_offset += iface->method.count;
1343 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1344 /* overwrite the imt slot only if we're building all the entries or if
1345 * we're building this specific one
1347 if (slot_num < 0 || i == slot_num) {
1348 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1351 if (imt_builder [i]) {
1352 MonoImtBuilderEntry *entry;
1354 /* Link entries with imt_builder [i] */
1355 for (entry = entries; entry->next; entry = entry->next) {
1357 MonoMethod *method = (MonoMethod*)entry->key;
1358 char *method_name = mono_method_full_name (method, TRUE);
1359 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1360 g_free (method_name);
1363 entry->next = imt_builder [i];
1364 entries->children += imt_builder [i]->children + 1;
1366 imt_builder [i] = entries;
1369 if (has_generic_virtual || has_variant_iface) {
1371 * There might be collisions later when the the thunk is expanded.
1373 imt_collisions_bitmap |= (1 << i);
1376 * The IMT thunk might be called with an instance of one of the
1377 * generic virtual methods, so has to fallback to the IMT trampoline.
1379 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline (i));
1381 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1384 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1388 if (imt_builder [i] != NULL) {
1389 int methods_in_slot = imt_builder [i]->children + 1;
1390 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1391 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1392 record_method_count_for_max_collisions = TRUE;
1394 method_count += methods_in_slot;
1398 mono_stats.imt_number_of_methods += method_count;
1399 if (record_method_count_for_max_collisions) {
1400 mono_stats.imt_method_count_when_max_collisions = method_count;
1403 for (i = 0; i < MONO_IMT_SIZE; i++) {
1404 MonoImtBuilderEntry* entry = imt_builder [i];
1405 while (entry != NULL) {
1406 MonoImtBuilderEntry* next = entry->next;
1412 /* we OR the bitmap since we may build just a single imt slot at a time */
1413 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1417 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1418 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1422 * mono_vtable_build_imt_slot:
1423 * @vtable: virtual object table struct
1424 * @imt_slot: slot in the IMT table
1426 * Fill the given @imt_slot in the IMT table of @vtable with
1427 * a trampoline or a thunk for the case of collisions.
1428 * This is part of the internal mono API.
1430 * LOCKING: Take the domain lock.
1433 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1435 gpointer *imt = (gpointer*)vtable;
1436 imt -= MONO_IMT_SIZE;
1437 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1439 /* no support for extra interfaces: the proxy objects will need
1440 * to build the complete IMT
1441 * Update and heck needs to ahppen inside the proper domain lock, as all
1442 * the changes made to a MonoVTable.
1444 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1445 mono_domain_lock (vtable->domain);
1446 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1447 if (imt [imt_slot] == callbacks.get_imt_trampoline (imt_slot))
1448 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1449 mono_domain_unlock (vtable->domain);
1450 mono_loader_unlock ();
1455 * The first two free list entries both belong to the wait list: The
1456 * first entry is the pointer to the head of the list and the second
1457 * entry points to the last element. That way appending and removing
1458 * the first element are both O(1) operations.
1460 #ifdef MONO_SMALL_CONFIG
1461 #define NUM_FREE_LISTS 6
1463 #define NUM_FREE_LISTS 12
1465 #define FIRST_FREE_LIST_SIZE 64
1466 #define MAX_WAIT_LENGTH 50
1467 #define THUNK_THRESHOLD 10
1470 * LOCKING: The domain lock must be held.
1473 init_thunk_free_lists (MonoDomain *domain)
1475 if (domain->thunk_free_lists)
1477 domain->thunk_free_lists = mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1481 list_index_for_size (int item_size)
1484 int size = FIRST_FREE_LIST_SIZE;
1486 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1495 * mono_method_alloc_generic_virtual_thunk:
1497 * @size: size in bytes
1499 * Allocs size bytes to be used for the code of a generic virtual
1500 * thunk. It's either allocated from the domain's code manager or
1501 * reused from a previously invalidated piece.
1503 * LOCKING: The domain lock must be held.
1506 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1508 static gboolean inited = FALSE;
1509 static int generic_virtual_thunks_size = 0;
1513 MonoThunkFreeList **l;
1515 init_thunk_free_lists (domain);
1517 size += sizeof (guint32);
1518 if (size < sizeof (MonoThunkFreeList))
1519 size = sizeof (MonoThunkFreeList);
1521 i = list_index_for_size (size);
1522 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1523 if ((*l)->size >= size) {
1524 MonoThunkFreeList *item = *l;
1526 return ((guint32*)item) + 1;
1530 /* no suitable item found - search lists of larger sizes */
1531 while (++i < NUM_FREE_LISTS) {
1532 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1535 g_assert (item->size > size);
1536 domain->thunk_free_lists [i] = item->next;
1537 return ((guint32*)item) + 1;
1540 /* still nothing found - allocate it */
1542 mono_counters_register ("Generic virtual thunk bytes",
1543 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1546 generic_virtual_thunks_size += size;
1548 p = mono_domain_code_reserve (domain, size);
1551 mono_domain_lock (domain);
1552 if (!domain->generic_virtual_thunks)
1553 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1554 g_hash_table_insert (domain->generic_virtual_thunks, p, p);
1555 mono_domain_unlock (domain);
1561 * LOCKING: The domain lock must be held.
1564 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1567 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1568 gboolean found = FALSE;
1570 mono_domain_lock (domain);
1571 if (!domain->generic_virtual_thunks)
1572 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1573 if (g_hash_table_lookup (domain->generic_virtual_thunks, l))
1575 mono_domain_unlock (domain);
1578 /* Not allocated by mono_method_alloc_generic_virtual_thunk (), i.e. AOT */
1580 init_thunk_free_lists (domain);
1582 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1583 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1584 int length = item->length;
1587 /* unlink the first item from the wait list */
1588 domain->thunk_free_lists [0] = item->next;
1589 domain->thunk_free_lists [0]->length = length - 1;
1591 i = list_index_for_size (item->size);
1593 /* put it in the free list */
1594 item->next = domain->thunk_free_lists [i];
1595 domain->thunk_free_lists [i] = item;
1599 if (domain->thunk_free_lists [1]) {
1600 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1601 domain->thunk_free_lists [0]->length++;
1603 g_assert (!domain->thunk_free_lists [0]);
1605 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1606 domain->thunk_free_lists [0]->length = 1;
1610 typedef struct _GenericVirtualCase {
1614 struct _GenericVirtualCase *next;
1615 } GenericVirtualCase;
1618 * get_generic_virtual_entries:
1620 * Return IMT entries for the generic virtual method instances and
1621 * variant interface methods for vtable slot
1624 static MonoImtBuilderEntry*
1625 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1627 GenericVirtualCase *list;
1628 MonoImtBuilderEntry *entries;
1630 mono_domain_lock (domain);
1631 if (!domain->generic_virtual_cases)
1632 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1634 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1637 for (; list; list = list->next) {
1638 MonoImtBuilderEntry *entry;
1640 if (list->count < THUNK_THRESHOLD)
1643 entry = g_new0 (MonoImtBuilderEntry, 1);
1644 entry->key = list->method;
1645 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1646 entry->has_target_code = 1;
1648 entry->children = entries->children + 1;
1649 entry->next = entries;
1653 mono_domain_unlock (domain);
1655 /* FIXME: Leaking memory ? */
1660 * mono_method_add_generic_virtual_invocation:
1662 * @vtable_slot: pointer to the vtable slot
1663 * @method: the inflated generic virtual method
1664 * @code: the method's code
1666 * Registers a call via unmanaged code to a generic virtual method
1667 * instantiation or variant interface method. If the number of calls reaches a threshold
1668 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1669 * virtual method thunk.
1672 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1673 gpointer *vtable_slot,
1674 MonoMethod *method, gpointer code)
1676 static gboolean inited = FALSE;
1677 static int num_added = 0;
1679 GenericVirtualCase *gvc, *list;
1680 MonoImtBuilderEntry *entries;
1684 mono_domain_lock (domain);
1685 if (!domain->generic_virtual_cases)
1686 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1688 /* Check whether the case was already added */
1689 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1692 if (gvc->method == method)
1697 /* If not found, make a new one */
1699 gvc = mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1700 gvc->method = method;
1703 gvc->next = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1705 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1708 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1714 if (++gvc->count == THUNK_THRESHOLD) {
1715 gpointer *old_thunk = *vtable_slot;
1716 gpointer vtable_trampoline = NULL;
1717 gpointer imt_trampoline = NULL;
1719 if ((gpointer)vtable_slot < (gpointer)vtable) {
1720 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1721 int imt_slot = MONO_IMT_SIZE + displacement;
1723 /* Force the rebuild of the thunk at the next call */
1724 imt_trampoline = callbacks.get_imt_trampoline (imt_slot);
1725 *vtable_slot = imt_trampoline;
1727 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline ((gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1729 entries = get_generic_virtual_entries (domain, vtable_slot);
1731 sorted = imt_sort_slot_entries (entries);
1733 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1737 MonoImtBuilderEntry *next = entries->next;
1742 for (i = 0; i < sorted->len; ++i)
1743 g_free (g_ptr_array_index (sorted, i));
1744 g_ptr_array_free (sorted, TRUE);
1747 #ifndef __native_client__
1748 /* We don't re-use any thunks as there is a lot of overhead */
1749 /* to deleting and re-using code in Native Client. */
1750 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1751 invalidate_generic_virtual_thunk (domain, old_thunk);
1755 mono_domain_unlock (domain);
1758 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error);
1761 * mono_class_vtable:
1762 * @domain: the application domain
1763 * @class: the class to initialize
1765 * VTables are domain specific because we create domain specific code, and
1766 * they contain the domain specific static class data.
1767 * On failure, NULL is returned, and class->exception_type is set.
1770 mono_class_vtable (MonoDomain *domain, MonoClass *class)
1772 return mono_class_vtable_full (domain, class, FALSE);
1776 * mono_class_vtable_full:
1777 * @domain: the application domain
1778 * @class: the class to initialize
1779 * @raise_on_error if an exception should be raised on failure or not
1781 * VTables are domain specific because we create domain specific code, and
1782 * they contain the domain specific static class data.
1785 mono_class_vtable_full (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1787 MonoClassRuntimeInfo *runtime_info;
1791 if (class->exception_type) {
1793 mono_raise_exception (mono_class_get_exception_for_failure (class));
1797 /* this check can be inlined in jitted code, too */
1798 runtime_info = class->runtime_info;
1799 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1800 return runtime_info->domain_vtables [domain->domain_id];
1801 return mono_class_create_runtime_vtable (domain, class, raise_on_error);
1805 * mono_class_try_get_vtable:
1806 * @domain: the application domain
1807 * @class: the class to initialize
1809 * This function tries to get the associated vtable from @class if
1810 * it was already created.
1813 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *class)
1815 MonoClassRuntimeInfo *runtime_info;
1819 runtime_info = class->runtime_info;
1820 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1821 return runtime_info->domain_vtables [domain->domain_id];
1826 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1828 size_t alloc_offset;
1831 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1832 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1833 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1835 if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1836 g_assert ((imt_table_bytes & 7) == 4);
1843 return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1847 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1850 MonoClassRuntimeInfo *runtime_info, *old_info;
1851 MonoClassField *field;
1853 int i, vtable_slots;
1854 size_t imt_table_bytes;
1856 guint32 vtable_size, class_size;
1858 gpointer *interface_offsets;
1860 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1861 mono_domain_lock (domain);
1862 runtime_info = class->runtime_info;
1863 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1864 mono_domain_unlock (domain);
1865 mono_loader_unlock ();
1866 return runtime_info->domain_vtables [domain->domain_id];
1868 if (!class->inited || class->exception_type) {
1869 if (!mono_class_init (class) || class->exception_type) {
1870 mono_domain_unlock (domain);
1871 mono_loader_unlock ();
1873 mono_raise_exception (mono_class_get_exception_for_failure (class));
1878 /* Array types require that their element type be valid*/
1879 if (class->byval_arg.type == MONO_TYPE_ARRAY || class->byval_arg.type == MONO_TYPE_SZARRAY) {
1880 MonoClass *element_class = class->element_class;
1881 if (!element_class->inited)
1882 mono_class_init (element_class);
1884 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1885 if (element_class->exception_type == MONO_EXCEPTION_NONE && !element_class->vtable_size)
1886 mono_class_setup_vtable (element_class);
1888 if (element_class->exception_type != MONO_EXCEPTION_NONE) {
1889 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1890 if (class->exception_type == MONO_EXCEPTION_NONE)
1891 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
1892 mono_domain_unlock (domain);
1893 mono_loader_unlock ();
1895 mono_raise_exception (mono_class_get_exception_for_failure (class));
1901 * For some classes, mono_class_init () already computed class->vtable_size, and
1902 * that is all that is needed because of the vtable trampolines.
1904 if (!class->vtable_size)
1905 mono_class_setup_vtable (class);
1907 if (class->generic_class && !class->vtable)
1908 mono_class_check_vtable_constraints (class, NULL);
1910 /* Initialize klass->has_finalize */
1911 mono_class_has_finalizer (class);
1913 if (class->exception_type) {
1914 mono_domain_unlock (domain);
1915 mono_loader_unlock ();
1917 mono_raise_exception (mono_class_get_exception_for_failure (class));
1921 vtable_slots = class->vtable_size;
1922 /* we add an additional vtable slot to store the pointer to static field data only when needed */
1923 class_size = mono_class_data_size (class);
1927 if (class->interface_offsets_count) {
1928 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1929 mono_stats.imt_number_of_tables++;
1930 mono_stats.imt_tables_size += imt_table_bytes;
1932 imt_table_bytes = 0;
1935 vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
1937 mono_stats.used_class_count++;
1938 mono_stats.class_vtable_size += vtable_size;
1940 interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
1941 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1942 g_assert (!((gsize)vt & 7));
1945 vt->rank = class->rank;
1946 vt->domain = domain;
1948 mono_class_compute_gc_descriptor (class);
1950 * We can't use typed allocation in the non-root domains, since the
1951 * collector needs the GC descriptor stored in the vtable even after
1952 * the mempool containing the vtable is destroyed when the domain is
1953 * unloaded. An alternative might be to allocate vtables in the GC
1954 * heap, but this does not seem to work (it leads to crashes inside
1955 * libgc). If that approach is tried, two gc descriptors need to be
1956 * allocated for each class: one for the root domain, and one for all
1957 * other domains. The second descriptor should contain a bit for the
1958 * vtable field in MonoObject, since we can no longer assume the
1959 * vtable is reachable by other roots after the appdomain is unloaded.
1961 #ifdef HAVE_BOEHM_GC
1962 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1963 vt->gc_descr = GC_NO_DESCRIPTOR;
1966 vt->gc_descr = class->gc_descr;
1968 gc_bits = mono_gc_get_vtable_bits (class);
1969 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
1971 vt->gc_bits = gc_bits;
1974 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
1975 if (class->has_static_refs) {
1976 gpointer statics_gc_descr;
1978 gsize default_bitmap [4] = {0};
1981 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1982 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
1983 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1984 vt->vtable [class->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr);
1985 mono_domain_add_class_static_data (domain, class, vt->vtable [class->vtable_size], NULL);
1986 if (bitmap != default_bitmap)
1989 vt->vtable [class->vtable_size] = mono_domain_alloc0 (domain, class_size);
1991 vt->has_static_fields = TRUE;
1992 mono_stats.class_static_data_size += class_size;
1996 while ((field = mono_class_get_fields (class, &iter))) {
1997 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1999 if (mono_field_is_deleted (field))
2001 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2002 gint32 special_static = class->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (class, field);
2003 if (special_static != SPECIAL_STATIC_NONE) {
2004 guint32 size, offset;
2006 gsize default_bitmap [4] = {0};
2011 if (mono_type_is_reference (field->type)) {
2012 default_bitmap [0] = 1;
2014 bitmap = default_bitmap;
2015 } else if (mono_type_is_struct (field->type)) {
2016 fclass = mono_class_from_mono_type (field->type);
2017 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
2018 numbits = max_set + 1;
2020 default_bitmap [0] = 0;
2022 bitmap = default_bitmap;
2024 size = mono_type_size (field->type, &align);
2025 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
2026 if (!domain->special_static_fields)
2027 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2028 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2029 if (bitmap != default_bitmap)
2032 * This marks the field as special static to speed up the
2033 * checks in mono_field_static_get/set_value ().
2039 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2040 MonoClass *fklass = mono_class_from_mono_type (field->type);
2041 const char *data = mono_field_get_data (field);
2043 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2044 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2045 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2048 if (fklass->valuetype) {
2049 memcpy (t, data, mono_class_value_size (fklass, NULL));
2051 /* it's a pointer type: add check */
2052 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2059 vt->max_interface_id = class->max_interface_id;
2060 vt->interface_bitmap = class->interface_bitmap;
2062 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2063 // class->name, class->interface_offsets_count);
2065 /* Initialize vtable */
2066 if (callbacks.get_vtable_trampoline) {
2067 // This also covers the AOT case
2068 for (i = 0; i < class->vtable_size; ++i) {
2069 vt->vtable [i] = callbacks.get_vtable_trampoline (i);
2072 mono_class_setup_vtable (class);
2074 for (i = 0; i < class->vtable_size; ++i) {
2077 if ((cm = class->vtable [i]))
2078 vt->vtable [i] = arch_create_jit_trampoline (cm);
2082 if (imt_table_bytes) {
2083 /* Now that the vtable is full, we can actually fill up the IMT */
2084 for (i = 0; i < MONO_IMT_SIZE; ++i)
2085 interface_offsets [i] = callbacks.get_imt_trampoline (i);
2089 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2090 * re-acquire them and check if another thread has created the vtable in the meantime.
2092 /* Special case System.MonoType to avoid infinite recursion */
2093 if (class != mono_defaults.monotype_class) {
2094 /*FIXME check for OOM*/
2095 vt->type = mono_type_get_object (domain, &class->byval_arg);
2096 if (mono_object_get_class (vt->type) != mono_defaults.monotype_class)
2097 /* This is unregistered in
2098 unregister_vtable_reflection_type() in
2100 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type);
2103 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (class));
2105 /* class_vtable_array keeps an array of created vtables
2107 g_ptr_array_add (domain->class_vtable_array, vt);
2108 /* class->runtime_info is protected by the loader lock, both when
2109 * it it enlarged and when it is stored info.
2113 * Store the vtable in class->runtime_info.
2114 * class->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2116 mono_memory_barrier ();
2118 old_info = class->runtime_info;
2119 if (old_info && old_info->max_domain >= domain->domain_id) {
2120 /* someone already created a large enough runtime info */
2121 old_info->domain_vtables [domain->domain_id] = vt;
2123 int new_size = domain->domain_id;
2125 new_size = MAX (new_size, old_info->max_domain);
2127 /* make the new size a power of two */
2129 while (new_size > i)
2132 /* this is a bounded memory retention issue: may want to
2133 * handle it differently when we'll have a rcu-like system.
2135 runtime_info = mono_image_alloc0 (class->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2136 runtime_info->max_domain = new_size - 1;
2137 /* copy the stuff from the older info */
2139 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2141 runtime_info->domain_vtables [domain->domain_id] = vt;
2143 mono_memory_barrier ();
2144 class->runtime_info = runtime_info;
2147 if (class == mono_defaults.monotype_class) {
2148 /*FIXME check for OOM*/
2149 vt->type = mono_type_get_object (domain, &class->byval_arg);
2150 if (mono_object_get_class (vt->type) != mono_defaults.monotype_class)
2151 /* This is unregistered in
2152 unregister_vtable_reflection_type() in
2154 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type);
2157 mono_domain_unlock (domain);
2158 mono_loader_unlock ();
2160 /* make sure the parent is initialized */
2161 /*FIXME shouldn't this fail the current type?*/
2163 mono_class_vtable_full (domain, class->parent, raise_on_error);
2168 #ifndef DISABLE_REMOTING
2170 * mono_class_proxy_vtable:
2171 * @domain: the application domain
2172 * @remove_class: the remote class
2174 * Creates a vtable for transparent proxies. It is basically
2175 * a copy of the real vtable of the class wrapped in @remote_class,
2176 * but all function pointers invoke the remoting functions, and
2177 * vtable->klass points to the transparent proxy class, and not to @class.
2180 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2183 MonoVTable *vt, *pvt;
2184 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2186 GSList *extra_interfaces = NULL;
2187 MonoClass *class = remote_class->proxy_class;
2188 gpointer *interface_offsets;
2191 size_t imt_table_bytes;
2193 #ifdef COMPRESSED_INTERFACE_BITMAP
2197 vt = mono_class_vtable (domain, class);
2198 g_assert (vt); /*FIXME property handle failure*/
2199 max_interface_id = vt->max_interface_id;
2201 /* Calculate vtable space for extra interfaces */
2202 for (j = 0; j < remote_class->interface_count; j++) {
2203 MonoClass* iclass = remote_class->interfaces[j];
2207 /*FIXME test for interfaces with variant generic arguments*/
2208 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
2209 continue; /* interface implemented by the class */
2210 if (g_slist_find (extra_interfaces, iclass))
2213 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2215 method_count = mono_class_num_methods (iclass);
2217 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2218 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2220 for (i = 0; i < ifaces->len; ++i) {
2221 MonoClass *ic = g_ptr_array_index (ifaces, i);
2222 /*FIXME test for interfaces with variant generic arguments*/
2223 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
2224 continue; /* interface implemented by the class */
2225 if (g_slist_find (extra_interfaces, ic))
2227 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2228 method_count += mono_class_num_methods (ic);
2230 g_ptr_array_free (ifaces, TRUE);
2233 extra_interface_vtsize += method_count * sizeof (gpointer);
2234 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2237 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2238 mono_stats.imt_number_of_tables++;
2239 mono_stats.imt_tables_size += imt_table_bytes;
2241 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2243 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2245 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2246 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2247 g_assert (!((gsize)pvt & 7));
2249 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer));
2251 pvt->klass = mono_defaults.transparent_proxy_class;
2252 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2253 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2255 /* initialize vtable */
2256 mono_class_setup_vtable (class);
2257 for (i = 0; i < class->vtable_size; ++i) {
2260 if ((cm = class->vtable [i]))
2261 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2263 pvt->vtable [i] = NULL;
2266 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2267 /* create trampolines for abstract methods */
2268 for (k = class; k; k = k->parent) {
2270 gpointer iter = NULL;
2271 while ((m = mono_class_get_methods (k, &iter)))
2272 if (!pvt->vtable [m->slot])
2273 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2277 pvt->max_interface_id = max_interface_id;
2278 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2279 #ifdef COMPRESSED_INTERFACE_BITMAP
2280 bitmap = g_malloc0 (bsize);
2282 bitmap = mono_domain_alloc0 (domain, bsize);
2285 for (i = 0; i < class->interface_offsets_count; ++i) {
2286 int interface_id = class->interfaces_packed [i]->interface_id;
2287 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2290 if (extra_interfaces) {
2291 int slot = class->vtable_size;
2297 /* Create trampolines for the methods of the interfaces */
2298 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2299 interf = list_item->data;
2301 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2305 while ((cm = mono_class_get_methods (interf, &iter)))
2306 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2308 slot += mono_class_num_methods (interf);
2312 /* Now that the vtable is full, we can actually fill up the IMT */
2313 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
2314 if (extra_interfaces) {
2315 g_slist_free (extra_interfaces);
2318 #ifdef COMPRESSED_INTERFACE_BITMAP
2319 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2320 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2321 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2324 pvt->interface_bitmap = bitmap;
2329 #endif /* DISABLE_REMOTING */
2332 * mono_class_field_is_special_static:
2334 * Returns whether @field is a thread/context static field.
2337 mono_class_field_is_special_static (MonoClassField *field)
2339 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2341 if (mono_field_is_deleted (field))
2343 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2344 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2351 * mono_class_field_get_special_static_type:
2352 * @field: The MonoClassField describing the field.
2354 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2355 * SPECIAL_STATIC_NONE otherwise.
2358 mono_class_field_get_special_static_type (MonoClassField *field)
2360 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2361 return SPECIAL_STATIC_NONE;
2362 if (mono_field_is_deleted (field))
2363 return SPECIAL_STATIC_NONE;
2364 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2365 return field_is_special_static (field->parent, field);
2366 return SPECIAL_STATIC_NONE;
2370 * mono_class_has_special_static_fields:
2372 * Returns whenever @klass has any thread/context static fields.
2375 mono_class_has_special_static_fields (MonoClass *klass)
2377 MonoClassField *field;
2381 while ((field = mono_class_get_fields (klass, &iter))) {
2382 g_assert (field->parent == klass);
2383 if (mono_class_field_is_special_static (field))
2390 #ifndef DISABLE_REMOTING
2392 * create_remote_class_key:
2393 * Creates an array of pointers that can be used as a hash key for a remote class.
2394 * The first element of the array is the number of pointers.
2397 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2402 if (remote_class == NULL) {
2403 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2404 key = g_malloc (sizeof(gpointer) * 3);
2405 key [0] = GINT_TO_POINTER (2);
2406 key [1] = mono_defaults.marshalbyrefobject_class;
2407 key [2] = extra_class;
2409 key = g_malloc (sizeof(gpointer) * 2);
2410 key [0] = GINT_TO_POINTER (1);
2411 key [1] = extra_class;
2414 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2415 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2416 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2417 key [1] = remote_class->proxy_class;
2419 // Keep the list of interfaces sorted
2420 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2421 if (extra_class && remote_class->interfaces [i] > extra_class) {
2422 key [j++] = extra_class;
2425 key [j] = remote_class->interfaces [i];
2428 key [j] = extra_class;
2430 // Replace the old class. The interface list is the same
2431 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2432 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2433 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2434 for (i = 0; i < remote_class->interface_count; i++)
2435 key [2 + i] = remote_class->interfaces [i];
2443 * copy_remote_class_key:
2445 * Make a copy of KEY in the domain and return the copy.
2448 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2450 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2451 gpointer *mp_key = mono_domain_alloc (domain, key_size);
2453 memcpy (mp_key, key, key_size);
2459 * mono_remote_class:
2460 * @domain: the application domain
2461 * @class_name: name of the remote class
2463 * Creates and initializes a MonoRemoteClass object for a remote type.
2465 * Can raise an exception on failure.
2468 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2471 MonoRemoteClass *rc;
2472 gpointer* key, *mp_key;
2475 key = create_remote_class_key (NULL, proxy_class);
2477 mono_domain_lock (domain);
2478 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2482 mono_domain_unlock (domain);
2486 name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
2487 if (!mono_error_ok (&error)) {
2489 mono_domain_unlock (domain);
2490 mono_error_raise_exception (&error);
2493 mp_key = copy_remote_class_key (domain, key);
2497 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2498 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2499 rc->interface_count = 1;
2500 rc->interfaces [0] = proxy_class;
2501 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2503 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2504 rc->interface_count = 0;
2505 rc->proxy_class = proxy_class;
2508 rc->default_vtable = NULL;
2509 rc->xdomain_vtable = NULL;
2510 rc->proxy_class_name = name;
2511 #ifndef DISABLE_PERFCOUNTERS
2512 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2515 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2517 mono_domain_unlock (domain);
2522 * clone_remote_class:
2523 * Creates a copy of the remote_class, adding the provided class or interface
2525 static MonoRemoteClass*
2526 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2528 MonoRemoteClass *rc;
2529 gpointer* key, *mp_key;
2531 key = create_remote_class_key (remote_class, extra_class);
2532 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2538 mp_key = copy_remote_class_key (domain, key);
2542 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2544 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2545 rc->proxy_class = remote_class->proxy_class;
2546 rc->interface_count = remote_class->interface_count + 1;
2548 // Keep the list of interfaces sorted, since the hash key of
2549 // the remote class depends on this
2550 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2551 if (remote_class->interfaces [i] > extra_class && i == j)
2552 rc->interfaces [j++] = extra_class;
2553 rc->interfaces [j] = remote_class->interfaces [i];
2556 rc->interfaces [j] = extra_class;
2558 // Replace the old class. The interface array is the same
2559 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2560 rc->proxy_class = extra_class;
2561 rc->interface_count = remote_class->interface_count;
2562 if (rc->interface_count > 0)
2563 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2566 rc->default_vtable = NULL;
2567 rc->xdomain_vtable = NULL;
2568 rc->proxy_class_name = remote_class->proxy_class_name;
2570 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2576 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2578 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2579 mono_domain_lock (domain);
2580 if (rp->target_domain_id != -1) {
2581 if (remote_class->xdomain_vtable == NULL)
2582 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2583 mono_domain_unlock (domain);
2584 mono_loader_unlock ();
2585 return remote_class->xdomain_vtable;
2587 if (remote_class->default_vtable == NULL) {
2590 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2591 klass = mono_class_from_mono_type (type);
2593 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)))
2594 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2597 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2600 mono_domain_unlock (domain);
2601 mono_loader_unlock ();
2602 return remote_class->default_vtable;
2606 * mono_upgrade_remote_class:
2607 * @domain: the application domain
2608 * @tproxy: the proxy whose remote class has to be upgraded.
2609 * @klass: class to which the remote class can be casted.
2611 * Updates the vtable of the remote class by adding the necessary method slots
2612 * and interface offsets so it can be safely casted to klass. klass can be a
2613 * class or an interface.
2616 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2618 MonoTransparentProxy *tproxy;
2619 MonoRemoteClass *remote_class;
2620 gboolean redo_vtable;
2622 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2623 mono_domain_lock (domain);
2625 tproxy = (MonoTransparentProxy*) proxy_object;
2626 remote_class = tproxy->remote_class;
2628 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2631 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2632 if (remote_class->interfaces [i] == klass)
2633 redo_vtable = FALSE;
2636 redo_vtable = (remote_class->proxy_class != klass);
2640 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2641 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2644 mono_domain_unlock (domain);
2645 mono_loader_unlock ();
2647 #endif /* DISABLE_REMOTING */
2651 * mono_object_get_virtual_method:
2652 * @obj: object to operate on.
2655 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2656 * the instance of a callvirt of method.
2659 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2662 MonoMethod **vtable;
2663 gboolean is_proxy = FALSE;
2664 MonoMethod *res = NULL;
2666 klass = mono_object_class (obj);
2667 #ifndef DISABLE_REMOTING
2668 if (klass == mono_defaults.transparent_proxy_class) {
2669 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2674 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2677 mono_class_setup_vtable (klass);
2678 vtable = klass->vtable;
2680 if (method->slot == -1) {
2681 /* method->slot might not be set for instances of generic methods */
2682 if (method->is_inflated) {
2683 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2684 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2687 g_assert_not_reached ();
2691 /* check method->slot is a valid index: perform isinstance? */
2692 if (method->slot != -1) {
2693 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2695 gboolean variance_used = FALSE;
2696 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2697 g_assert (iface_offset > 0);
2698 res = vtable [iface_offset + method->slot];
2701 res = vtable [method->slot];
2705 #ifndef DISABLE_REMOTING
2707 /* It may be an interface, abstract class method or generic method */
2708 if (!res || mono_method_signature (res)->generic_param_count)
2711 /* generic methods demand invoke_with_check */
2712 if (mono_method_signature (res)->generic_param_count)
2713 res = mono_marshal_get_remoting_invoke_with_check (res);
2716 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2717 res = mono_cominterop_get_invoke (res);
2720 res = mono_marshal_get_remoting_invoke (res);
2725 if (method->is_inflated) {
2727 /* Have to inflate the result */
2728 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, &error);
2729 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
2739 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2741 g_error ("runtime invoke called on uninitialized runtime");
2745 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2748 * mono_runtime_invoke:
2749 * @method: method to invoke
2750 * @obJ: object instance
2751 * @params: arguments to the method
2752 * @exc: exception information.
2754 * Invokes the method represented by @method on the object @obj.
2756 * obj is the 'this' pointer, it should be NULL for static
2757 * methods, a MonoObject* for object instances and a pointer to
2758 * the value type for value types.
2760 * The params array contains the arguments to the method with the
2761 * same convention: MonoObject* pointers for object instances and
2762 * pointers to the value type otherwise.
2764 * From unmanaged code you'll usually use the
2765 * mono_runtime_invoke() variant.
2767 * Note that this function doesn't handle virtual methods for
2768 * you, it will exec the exact method you pass: we still need to
2769 * expose a function to lookup the derived class implementation
2770 * of a virtual method (there are examples of this in the code,
2773 * You can pass NULL as the exc argument if you don't want to
2774 * catch exceptions, otherwise, *exc will be set to the exception
2775 * thrown, if any. if an exception is thrown, you can't use the
2776 * MonoObject* result from the function.
2778 * If the method returns a value type, it is boxed in an object
2782 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2786 if (mono_runtime_get_no_exec ())
2787 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2789 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2790 mono_profiler_method_start_invoke (method);
2792 result = default_mono_runtime_invoke (method, obj, params, exc);
2794 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2795 mono_profiler_method_end_invoke (method);
2801 * mono_method_get_unmanaged_thunk:
2802 * @method: method to generate a thunk for.
2804 * Returns an unmanaged->managed thunk that can be used to call
2805 * a managed method directly from C.
2807 * The thunk's C signature closely matches the managed signature:
2809 * C#: public bool Equals (object obj);
2810 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2811 * MonoObject*, MonoException**);
2813 * The 1st ("this") parameter must not be used with static methods:
2815 * C#: public static bool ReferenceEquals (object a, object b);
2816 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2819 * The last argument must be a non-null pointer of a MonoException* pointer.
2820 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2821 * exception has been thrown in managed code. Otherwise it will point
2822 * to the MonoException* caught by the thunk. In this case, the result of
2823 * the thunk is undefined:
2825 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2826 * MonoException *ex = NULL;
2827 * Equals func = mono_method_get_unmanaged_thunk (method);
2828 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2830 * // handle exception
2833 * The calling convention of the thunk matches the platform's default
2834 * convention. This means that under Windows, C declarations must
2835 * contain the __stdcall attribute:
2837 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2838 * MonoObject*, MonoException**);
2842 * Value type arguments and return values are treated as they were objects:
2844 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2845 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2847 * Arguments must be properly boxed upon trunk's invocation, while return
2848 * values must be unboxed.
2851 mono_method_get_unmanaged_thunk (MonoMethod *method)
2853 method = mono_marshal_get_thunk_invoke_wrapper (method);
2854 return mono_compile_method (method);
2858 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
2862 /* object fields cannot be byref, so we don't need a
2864 gpointer *p = (gpointer*)dest;
2871 case MONO_TYPE_BOOLEAN:
2873 case MONO_TYPE_U1: {
2874 guint8 *p = (guint8*)dest;
2875 *p = value ? *(guint8*)value : 0;
2880 case MONO_TYPE_CHAR: {
2881 guint16 *p = (guint16*)dest;
2882 *p = value ? *(guint16*)value : 0;
2885 #if SIZEOF_VOID_P == 4
2890 case MONO_TYPE_U4: {
2891 gint32 *p = (gint32*)dest;
2892 *p = value ? *(gint32*)value : 0;
2895 #if SIZEOF_VOID_P == 8
2900 case MONO_TYPE_U8: {
2901 gint64 *p = (gint64*)dest;
2902 *p = value ? *(gint64*)value : 0;
2905 case MONO_TYPE_R4: {
2906 float *p = (float*)dest;
2907 *p = value ? *(float*)value : 0;
2910 case MONO_TYPE_R8: {
2911 double *p = (double*)dest;
2912 *p = value ? *(double*)value : 0;
2915 case MONO_TYPE_STRING:
2916 case MONO_TYPE_SZARRAY:
2917 case MONO_TYPE_CLASS:
2918 case MONO_TYPE_OBJECT:
2919 case MONO_TYPE_ARRAY:
2920 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2922 case MONO_TYPE_FNPTR:
2923 case MONO_TYPE_PTR: {
2924 gpointer *p = (gpointer*)dest;
2925 *p = deref_pointer? *(gpointer*)value: value;
2928 case MONO_TYPE_VALUETYPE:
2929 /* note that 't' and 'type->type' can be different */
2930 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
2931 t = mono_class_enum_basetype (type->data.klass)->type;
2934 MonoClass *class = mono_class_from_mono_type (type);
2935 int size = mono_class_value_size (class, NULL);
2937 mono_gc_bzero_atomic (dest, size);
2939 mono_gc_wbarrier_value_copy (dest, value, 1, class);
2942 case MONO_TYPE_GENERICINST:
2943 t = type->data.generic_class->container_class->byval_arg.type;
2946 g_error ("got type %x", type->type);
2951 * mono_field_set_value:
2952 * @obj: Instance object
2953 * @field: MonoClassField describing the field to set
2954 * @value: The value to be set
2956 * Sets the value of the field described by @field in the object instance @obj
2957 * to the value passed in @value. This method should only be used for instance
2958 * fields. For static fields, use mono_field_static_set_value.
2960 * The value must be on the native format of the field type.
2963 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
2967 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2969 dest = (char*)obj + field->offset;
2970 mono_copy_value (field->type, dest, value, FALSE);
2974 * mono_field_static_set_value:
2975 * @field: MonoClassField describing the field to set
2976 * @value: The value to be set
2978 * Sets the value of the static field described by @field
2979 * to the value passed in @value.
2981 * The value must be on the native format of the field type.
2984 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
2988 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2989 /* you cant set a constant! */
2990 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
2992 if (field->offset == -1) {
2993 /* Special static */
2996 mono_domain_lock (vt->domain);
2997 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
2998 mono_domain_unlock (vt->domain);
2999 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3001 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3003 mono_copy_value (field->type, dest, value, FALSE);
3007 * mono_vtable_get_static_field_data:
3009 * Internal use function: return a pointer to the memory holding the static fields
3010 * for a class or NULL if there are no static fields.
3011 * This is exported only for use by the debugger.
3014 mono_vtable_get_static_field_data (MonoVTable *vt)
3016 if (!vt->has_static_fields)
3018 return vt->vtable [vt->klass->vtable_size];
3022 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3026 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3027 if (field->offset == -1) {
3028 /* Special static */
3031 mono_domain_lock (vt->domain);
3032 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3033 mono_domain_unlock (vt->domain);
3034 src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3036 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3039 src = (guint8*)obj + field->offset;
3046 * mono_field_get_value:
3047 * @obj: Object instance
3048 * @field: MonoClassField describing the field to fetch information from
3049 * @value: pointer to the location where the value will be stored
3051 * Use this routine to get the value of the field @field in the object
3054 * The pointer provided by value must be of the field type, for reference
3055 * types this is a MonoObject*, for value types its the actual pointer to
3060 * mono_field_get_value (obj, int_field, &i);
3063 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3069 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3071 src = (char*)obj + field->offset;
3072 mono_copy_value (field->type, value, src, TRUE);
3076 * mono_field_get_value_object:
3077 * @domain: domain where the object will be created (if boxing)
3078 * @field: MonoClassField describing the field to fetch information from
3079 * @obj: The object instance for the field.
3081 * Returns: a new MonoObject with the value from the given field. If the
3082 * field represents a value type, the value is boxed.
3086 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3090 MonoVTable *vtable = NULL;
3092 gboolean is_static = FALSE;
3093 gboolean is_ref = FALSE;
3094 gboolean is_literal = FALSE;
3095 gboolean is_ptr = FALSE;
3097 MonoType *type = mono_field_get_type_checked (field, &error);
3099 if (!mono_error_ok (&error))
3100 mono_error_raise_exception (&error);
3102 switch (type->type) {
3103 case MONO_TYPE_STRING:
3104 case MONO_TYPE_OBJECT:
3105 case MONO_TYPE_CLASS:
3106 case MONO_TYPE_ARRAY:
3107 case MONO_TYPE_SZARRAY:
3112 case MONO_TYPE_BOOLEAN:
3115 case MONO_TYPE_CHAR:
3124 case MONO_TYPE_VALUETYPE:
3125 is_ref = type->byref;
3127 case MONO_TYPE_GENERICINST:
3128 is_ref = !mono_type_generic_inst_is_valuetype (type);
3134 g_error ("type 0x%x not handled in "
3135 "mono_field_get_value_object", type->type);
3139 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3142 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3146 vtable = mono_class_vtable_full (domain, field->parent, TRUE);
3147 if (!vtable->initialized)
3148 mono_runtime_class_init (vtable);
3156 get_default_field_value (domain, field, &o);
3157 } else if (is_static) {
3158 mono_field_static_get_value (vtable, field, &o);
3160 mono_field_get_value (obj, field, &o);
3166 static MonoMethod *m;
3172 MonoClass *ptr_klass = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
3173 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3179 get_default_field_value (domain, field, v);
3180 } else if (is_static) {
3181 mono_field_static_get_value (vtable, field, v);
3183 mono_field_get_value (obj, field, v);
3186 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3187 args [0] = ptr ? *ptr : NULL;
3188 args [1] = mono_type_get_object (mono_domain_get (), type);
3190 return mono_runtime_invoke (m, NULL, args, NULL);
3193 /* boxed value type */
3194 klass = mono_class_from_mono_type (type);
3196 if (mono_class_is_nullable (klass))
3197 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
3199 o = mono_object_new (domain, klass);
3200 v = ((gchar *) o) + sizeof (MonoObject);
3203 get_default_field_value (domain, field, v);
3204 } else if (is_static) {
3205 mono_field_static_get_value (vtable, field, v);
3207 mono_field_get_value (obj, field, v);
3214 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
3217 const char *p = blob;
3218 mono_metadata_decode_blob_size (p, &p);
3221 case MONO_TYPE_BOOLEAN:
3224 *(guint8 *) value = *p;
3226 case MONO_TYPE_CHAR:
3229 *(guint16*) value = read16 (p);
3233 *(guint32*) value = read32 (p);
3237 *(guint64*) value = read64 (p);
3240 readr4 (p, (float*) value);
3243 readr8 (p, (double*) value);
3245 case MONO_TYPE_STRING:
3246 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3248 case MONO_TYPE_CLASS:
3249 *(gpointer*) value = NULL;
3253 g_warning ("type 0x%02x should not be in constant table", type);
3259 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3261 MonoTypeEnum def_type;
3264 data = mono_class_get_field_default_value (field, &def_type);
3265 mono_get_constant_value_from_blob (domain, def_type, data, value);
3269 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value)
3273 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3275 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3276 get_default_field_value (vt->domain, field, value);
3280 if (field->offset == -1) {
3281 /* Special static */
3282 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3283 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3285 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3287 mono_copy_value (field->type, value, src, TRUE);
3291 * mono_field_static_get_value:
3292 * @vt: vtable to the object
3293 * @field: MonoClassField describing the field to fetch information from
3294 * @value: where the value is returned
3296 * Use this routine to get the value of the static field @field value.
3298 * The pointer provided by value must be of the field type, for reference
3299 * types this is a MonoObject*, for value types its the actual pointer to
3304 * mono_field_static_get_value (vt, int_field, &i);
3307 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3309 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value);
3313 * mono_property_set_value:
3314 * @prop: MonoProperty to set
3315 * @obj: instance object on which to act
3316 * @params: parameters to pass to the propery
3317 * @exc: optional exception
3319 * Invokes the property's set method with the given arguments on the
3320 * object instance obj (or NULL for static properties).
3322 * You can pass NULL as the exc argument if you don't want to
3323 * catch exceptions, otherwise, *exc will be set to the exception
3324 * thrown, if any. if an exception is thrown, you can't use the
3325 * MonoObject* result from the function.
3328 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3330 default_mono_runtime_invoke (prop->set, obj, params, exc);
3334 * mono_property_get_value:
3335 * @prop: MonoProperty to fetch
3336 * @obj: instance object on which to act
3337 * @params: parameters to pass to the propery
3338 * @exc: optional exception
3340 * Invokes the property's get method with the given arguments on the
3341 * object instance obj (or NULL for static properties).
3343 * You can pass NULL as the exc argument if you don't want to
3344 * catch exceptions, otherwise, *exc will be set to the exception
3345 * thrown, if any. if an exception is thrown, you can't use the
3346 * MonoObject* result from the function.
3348 * Returns: the value from invoking the get method on the property.
3351 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3353 return default_mono_runtime_invoke (prop->get, obj, params, exc);
3357 * mono_nullable_init:
3358 * @buf: The nullable structure to initialize.
3359 * @value: the value to initialize from
3360 * @klass: the type for the object
3362 * Initialize the nullable structure pointed to by @buf from @value which
3363 * should be a boxed value type. The size of @buf should be able to hold
3364 * as much data as the @klass->instance_size (which is the number of bytes
3365 * that will be copies).
3367 * Since Nullables have variable structure, we can not define a C
3368 * structure for them.
3371 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3373 MonoClass *param_class = klass->cast_class;
3375 mono_class_setup_fields_locking (klass);
3376 g_assert (klass->fields_inited);
3378 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3379 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3381 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3383 if (param_class->has_references)
3384 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3386 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3388 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3393 * mono_nullable_box:
3394 * @buf: The buffer representing the data to be boxed
3395 * @klass: the type to box it as.
3397 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3401 mono_nullable_box (guint8 *buf, MonoClass *klass)
3403 MonoClass *param_class = klass->cast_class;
3405 mono_class_setup_fields_locking (klass);
3406 g_assert (klass->fields_inited);
3408 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3409 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3411 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3412 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
3413 if (param_class->has_references)
3414 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3416 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3424 * mono_get_delegate_invoke:
3425 * @klass: The delegate class
3427 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3430 mono_get_delegate_invoke (MonoClass *klass)
3434 /* This is called at runtime, so avoid the slower search in metadata */
3435 mono_class_setup_methods (klass);
3436 if (klass->exception_type)
3438 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3443 * mono_get_delegate_begin_invoke:
3444 * @klass: The delegate class
3446 * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3449 mono_get_delegate_begin_invoke (MonoClass *klass)
3453 /* This is called at runtime, so avoid the slower search in metadata */
3454 mono_class_setup_methods (klass);
3455 if (klass->exception_type)
3457 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3462 * mono_get_delegate_end_invoke:
3463 * @klass: The delegate class
3465 * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3468 mono_get_delegate_end_invoke (MonoClass *klass)
3472 /* This is called at runtime, so avoid the slower search in metadata */
3473 mono_class_setup_methods (klass);
3474 if (klass->exception_type)
3476 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3481 * mono_runtime_delegate_invoke:
3482 * @delegate: pointer to a delegate object.
3483 * @params: parameters for the delegate.
3484 * @exc: Pointer to the exception result.
3486 * Invokes the delegate method @delegate with the parameters provided.
3488 * You can pass NULL as the exc argument if you don't want to
3489 * catch exceptions, otherwise, *exc will be set to the exception
3490 * thrown, if any. if an exception is thrown, you can't use the
3491 * MonoObject* result from the function.
3494 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3497 MonoClass *klass = delegate->vtable->klass;
3499 im = mono_get_delegate_invoke (klass);
3501 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3503 return mono_runtime_invoke (im, delegate, params, exc);
3506 static char **main_args = NULL;
3507 static int num_main_args = 0;
3510 * mono_runtime_get_main_args:
3512 * Returns: a MonoArray with the arguments passed to the main program
3515 mono_runtime_get_main_args (void)
3519 MonoDomain *domain = mono_domain_get ();
3521 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3523 for (i = 0; i < num_main_args; ++i)
3524 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3530 free_main_args (void)
3534 for (i = 0; i < num_main_args; ++i)
3535 g_free (main_args [i]);
3542 * mono_runtime_set_main_args:
3543 * @argc: number of arguments from the command line
3544 * @argv: array of strings from the command line
3546 * Set the command line arguments from an embedding application that doesn't otherwise call
3547 * mono_runtime_run_main ().
3550 mono_runtime_set_main_args (int argc, char* argv[])
3555 main_args = g_new0 (char*, argc);
3556 num_main_args = argc;
3558 for (i = 0; i < argc; ++i) {
3561 utf8_arg = mono_utf8_from_external (argv[i]);
3562 if (utf8_arg == NULL) {
3563 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
3564 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3568 main_args [i] = utf8_arg;
3575 * mono_runtime_run_main:
3576 * @method: the method to start the application with (usually Main)
3577 * @argc: number of arguments from the command line
3578 * @argv: array of strings from the command line
3579 * @exc: excetption results
3581 * Execute a standard Main() method (argc/argv contains the
3582 * executable name). This method also sets the command line argument value
3583 * needed by System.Environment.
3588 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3592 MonoArray *args = NULL;
3593 MonoDomain *domain = mono_domain_get ();
3594 gchar *utf8_fullpath;
3595 MonoMethodSignature *sig;
3597 g_assert (method != NULL);
3599 mono_thread_set_main (mono_thread_current ());
3601 main_args = g_new0 (char*, argc);
3602 num_main_args = argc;
3604 if (!g_path_is_absolute (argv [0])) {
3605 gchar *basename = g_path_get_basename (argv [0]);
3606 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3610 utf8_fullpath = mono_utf8_from_external (fullpath);
3611 if(utf8_fullpath == NULL) {
3612 /* Printing the arg text will cause glib to
3613 * whinge about "Invalid UTF-8", but at least
3614 * its relevant, and shows the problem text
3617 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3618 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3625 utf8_fullpath = mono_utf8_from_external (argv[0]);
3626 if(utf8_fullpath == NULL) {
3627 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3628 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3633 main_args [0] = utf8_fullpath;
3635 for (i = 1; i < argc; ++i) {
3638 utf8_arg=mono_utf8_from_external (argv[i]);
3639 if(utf8_arg==NULL) {
3640 /* Ditto the comment about Invalid UTF-8 here */
3641 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3642 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3646 main_args [i] = utf8_arg;
3651 sig = mono_method_signature (method);
3653 g_print ("Unable to load Main method.\n");
3657 if (sig->param_count) {
3658 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3659 for (i = 0; i < argc; ++i) {
3660 /* The encodings should all work, given that
3661 * we've checked all these args for the
3664 gchar *str = mono_utf8_from_external (argv [i]);
3665 MonoString *arg = mono_string_new (domain, str);
3666 mono_array_setref (args, i, arg);
3670 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3673 mono_assembly_set_main (method->klass->image->assembly);
3675 return mono_runtime_exec_main (method, args, exc);
3679 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3681 static MonoMethod *serialize_method;
3686 if (!serialize_method) {
3687 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3688 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
3691 if (!serialize_method) {
3696 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
3700 array = mono_runtime_invoke (serialize_method, NULL, params, exc);
3708 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3710 static MonoMethod *deserialize_method;
3715 if (!deserialize_method) {
3716 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3717 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
3719 if (!deserialize_method) {
3726 result = mono_runtime_invoke (deserialize_method, NULL, params, exc);
3733 #ifndef DISABLE_REMOTING
3735 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
3737 static MonoMethod *get_proxy_method;
3739 MonoDomain *domain = mono_domain_get ();
3740 MonoRealProxy *real_proxy;
3741 MonoReflectionType *reflection_type;
3742 MonoTransparentProxy *transparent_proxy;
3744 if (!get_proxy_method)
3745 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
3747 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
3749 real_proxy = (MonoRealProxy*) mono_object_new (domain, mono_defaults.real_proxy_class);
3750 reflection_type = mono_type_get_object (domain, &obj->vtable->klass->byval_arg);
3752 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
3753 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
3756 transparent_proxy = (MonoTransparentProxy*) mono_runtime_invoke (get_proxy_method, real_proxy, NULL, exc);
3760 return (MonoObject*) transparent_proxy;
3762 #endif /* DISABLE_REMOTING */
3765 * mono_object_xdomain_representation
3767 * @target_domain: a domain
3768 * @exc: pointer to a MonoObject*
3770 * Creates a representation of obj in the domain target_domain. This
3771 * is either a copy of obj arrived through via serialization and
3772 * deserialization or a proxy, depending on whether the object is
3773 * serializable or marshal by ref. obj must not be in target_domain.
3775 * If the object cannot be represented in target_domain, NULL is
3776 * returned and *exc is set to an appropriate exception.
3779 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
3781 MonoObject *deserialized = NULL;
3782 gboolean failure = FALSE;
3786 #ifndef DISABLE_REMOTING
3787 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
3788 deserialized = make_transparent_proxy (obj, &failure, exc);
3793 MonoDomain *domain = mono_domain_get ();
3794 MonoObject *serialized;
3796 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
3797 serialized = serialize_object (obj, &failure, exc);
3798 mono_domain_set_internal_with_options (target_domain, FALSE);
3800 deserialized = deserialize_object (serialized, &failure, exc);
3801 if (domain != target_domain)
3802 mono_domain_set_internal_with_options (domain, FALSE);
3805 return deserialized;
3808 /* Used in call_unhandled_exception_delegate */
3810 create_unhandled_exception_eventargs (MonoObject *exc)
3814 MonoMethod *method = NULL;
3815 MonoBoolean is_terminating = TRUE;
3818 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
3821 mono_class_init (klass);
3823 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
3824 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
3828 args [1] = &is_terminating;
3830 obj = mono_object_new (mono_domain_get (), klass);
3831 mono_runtime_invoke (method, obj, args, NULL);
3836 /* Used in mono_unhandled_exception */
3838 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
3839 MonoObject *e = NULL;
3841 MonoDomain *current_domain = mono_domain_get ();
3843 if (domain != current_domain)
3844 mono_domain_set_internal_with_options (domain, FALSE);
3846 g_assert (domain == mono_object_domain (domain->domain));
3848 if (mono_object_domain (exc) != domain) {
3849 MonoObject *serialization_exc;
3851 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
3853 if (serialization_exc) {
3855 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
3858 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
3859 "System.Runtime.Serialization", "SerializationException",
3860 "Could not serialize unhandled exception.");
3864 g_assert (mono_object_domain (exc) == domain);
3866 pa [0] = domain->domain;
3867 pa [1] = create_unhandled_exception_eventargs (exc);
3868 mono_runtime_delegate_invoke (delegate, pa, &e);
3870 if (domain != current_domain)
3871 mono_domain_set_internal_with_options (current_domain, FALSE);
3875 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
3876 if (!mono_error_ok (&error)) {
3877 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
3878 mono_error_cleanup (&error);
3880 g_warning ("exception inside UnhandledException handler: %s\n", msg);
3886 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
3889 * mono_runtime_unhandled_exception_policy_set:
3890 * @policy: the new policy
3892 * This is a VM internal routine.
3894 * Sets the runtime policy for handling unhandled exceptions.
3897 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
3898 runtime_unhandled_exception_policy = policy;
3902 * mono_runtime_unhandled_exception_policy_get:
3904 * This is a VM internal routine.
3906 * Gets the runtime policy for handling unhandled exceptions.
3908 MonoRuntimeUnhandledExceptionPolicy
3909 mono_runtime_unhandled_exception_policy_get (void) {
3910 return runtime_unhandled_exception_policy;
3914 * mono_unhandled_exception:
3915 * @exc: exception thrown
3917 * This is a VM internal routine.
3919 * We call this function when we detect an unhandled exception
3920 * in the default domain.
3922 * It invokes the * UnhandledException event in AppDomain or prints
3923 * a warning to the console
3926 mono_unhandled_exception (MonoObject *exc)
3928 MonoDomain *current_domain = mono_domain_get ();
3929 MonoDomain *root_domain = mono_get_root_domain ();
3930 MonoClassField *field;
3931 MonoObject *current_appdomain_delegate;
3932 MonoObject *root_appdomain_delegate;
3934 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
3935 "UnhandledException");
3938 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
3939 gboolean abort_process = (main_thread && (mono_thread_internal_current () == main_thread->internal_thread)) ||
3940 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT);
3941 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
3942 if (current_domain != root_domain) {
3943 current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
3945 current_appdomain_delegate = NULL;
3948 /* set exitcode only if we will abort the process */
3949 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
3951 mono_environment_exitcode_set (1);
3952 mono_print_unhandled_exception (exc);
3954 if (root_appdomain_delegate) {
3955 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
3957 if (current_appdomain_delegate) {
3958 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
3965 * mono_runtime_exec_managed_code:
3966 * @domain: Application domain
3967 * @main_func: function to invoke from the execution thread
3968 * @main_args: parameter to the main_func
3970 * Launch a new thread to execute a function
3972 * main_func is called back from the thread with main_args as the
3973 * parameter. The callback function is expected to start Main()
3974 * eventually. This function then waits for all managed threads to
3976 * It is not necesseray anymore to execute managed code in a subthread,
3977 * so this function should not be used anymore by default: just
3978 * execute the code and then call mono_thread_manage ().
3981 mono_runtime_exec_managed_code (MonoDomain *domain,
3982 MonoMainThreadFunc main_func,
3985 mono_thread_create (domain, main_func, main_args);
3987 mono_thread_manage ();
3991 * Execute a standard Main() method (args doesn't contain the
3995 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4000 MonoCustomAttrInfo* cinfo;
4001 gboolean has_stathread_attribute;
4002 MonoInternalThread* thread = mono_thread_internal_current ();
4008 domain = mono_object_domain (args);
4009 if (!domain->entry_assembly) {
4011 MonoAssembly *assembly;
4013 assembly = method->klass->image->assembly;
4014 domain->entry_assembly = assembly;
4015 /* Domains created from another domain already have application_base and configuration_file set */
4016 if (domain->setup->application_base == NULL) {
4017 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4020 if (domain->setup->configuration_file == NULL) {
4021 str = g_strconcat (assembly->image->name, ".config", NULL);
4022 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4024 mono_set_private_bin_path_from_config (domain);
4028 cinfo = mono_custom_attrs_from_method (method);
4030 static MonoClass *stathread_attribute = NULL;
4031 if (!stathread_attribute)
4032 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
4033 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
4035 mono_custom_attrs_free (cinfo);
4037 has_stathread_attribute = FALSE;
4039 if (has_stathread_attribute) {
4040 thread->apartment_state = ThreadApartmentState_STA;
4042 thread->apartment_state = ThreadApartmentState_MTA;
4044 mono_thread_init_apartment_state ();
4046 /* FIXME: check signature of method */
4047 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4049 res = mono_runtime_invoke (method, NULL, pa, exc);
4051 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4055 mono_environment_exitcode_set (rval);
4057 mono_runtime_invoke (method, NULL, pa, exc);
4061 /* If the return type of Main is void, only
4062 * set the exitcode if an exception was thrown
4063 * (we don't want to blow away an
4064 * explicitly-set exit code)
4067 mono_environment_exitcode_set (rval);
4075 * mono_install_runtime_invoke:
4076 * @func: Function to install
4078 * This is a VM internal routine
4081 mono_install_runtime_invoke (MonoInvokeFunc func)
4083 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
4088 * mono_runtime_invoke_array:
4089 * @method: method to invoke
4090 * @obJ: object instance
4091 * @params: arguments to the method
4092 * @exc: exception information.
4094 * Invokes the method represented by @method on the object @obj.
4096 * obj is the 'this' pointer, it should be NULL for static
4097 * methods, a MonoObject* for object instances and a pointer to
4098 * the value type for value types.
4100 * The params array contains the arguments to the method with the
4101 * same convention: MonoObject* pointers for object instances and
4102 * pointers to the value type otherwise. The _invoke_array
4103 * variant takes a C# object[] as the params argument (MonoArray
4104 * *params): in this case the value types are boxed inside the
4105 * respective reference representation.
4107 * From unmanaged code you'll usually use the
4108 * mono_runtime_invoke() variant.
4110 * Note that this function doesn't handle virtual methods for
4111 * you, it will exec the exact method you pass: we still need to
4112 * expose a function to lookup the derived class implementation
4113 * of a virtual method (there are examples of this in the code,
4116 * You can pass NULL as the exc argument if you don't want to
4117 * catch exceptions, otherwise, *exc will be set to the exception
4118 * thrown, if any. if an exception is thrown, you can't use the
4119 * MonoObject* result from the function.
4121 * If the method returns a value type, it is boxed in an object
4125 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4128 MonoMethodSignature *sig = mono_method_signature (method);
4129 gpointer *pa = NULL;
4132 gboolean has_byref_nullables = FALSE;
4134 if (NULL != params) {
4135 pa = alloca (sizeof (gpointer) * mono_array_length (params));
4136 for (i = 0; i < mono_array_length (params); i++) {
4137 MonoType *t = sig->params [i];
4143 case MONO_TYPE_BOOLEAN:
4146 case MONO_TYPE_CHAR:
4155 case MONO_TYPE_VALUETYPE:
4156 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
4157 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4158 pa [i] = mono_array_get (params, MonoObject*, i);
4160 has_byref_nullables = TRUE;
4162 /* MS seems to create the objects if a null is passed in */
4163 if (!mono_array_get (params, MonoObject*, i))
4164 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
4168 * We can't pass the unboxed vtype byref to the callee, since
4169 * that would mean the callee would be able to modify boxed
4170 * primitive types. So we (and MS) make a copy of the boxed
4171 * object, pass that to the callee, and replace the original
4172 * boxed object in the arg array with the copy.
4174 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4175 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
4176 mono_array_setref (params, i, copy);
4179 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4182 case MONO_TYPE_STRING:
4183 case MONO_TYPE_OBJECT:
4184 case MONO_TYPE_CLASS:
4185 case MONO_TYPE_ARRAY:
4186 case MONO_TYPE_SZARRAY:
4188 pa [i] = mono_array_addr (params, MonoObject*, i);
4189 // FIXME: I need to check this code path
4191 pa [i] = mono_array_get (params, MonoObject*, i);
4193 case MONO_TYPE_GENERICINST:
4195 t = &t->data.generic_class->container_class->this_arg;
4197 t = &t->data.generic_class->container_class->byval_arg;
4199 case MONO_TYPE_PTR: {
4202 /* The argument should be an IntPtr */
4203 arg = mono_array_get (params, MonoObject*, i);
4207 g_assert (arg->vtable->klass == mono_defaults.int_class);
4208 pa [i] = ((MonoIntPtr*)arg)->m_value;
4213 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
4218 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4221 if (mono_class_is_nullable (method->klass)) {
4222 /* Need to create a boxed vtype instead */
4228 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
4232 obj = mono_object_new (mono_domain_get (), method->klass);
4233 g_assert (obj); /*maybe we should raise a TLE instead?*/
4234 #ifndef DISABLE_REMOTING
4235 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
4236 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
4239 if (method->klass->valuetype)
4240 o = mono_object_unbox (obj);
4243 } else if (method->klass->valuetype) {
4244 obj = mono_value_box (mono_domain_get (), method->klass, obj);
4247 mono_runtime_invoke (method, o, pa, exc);
4250 if (mono_class_is_nullable (method->klass)) {
4251 MonoObject *nullable;
4253 /* Convert the unboxed vtype into a Nullable structure */
4254 nullable = mono_object_new (mono_domain_get (), method->klass);
4256 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
4257 obj = mono_object_unbox (nullable);
4260 /* obj must be already unboxed if needed */
4261 res = mono_runtime_invoke (method, obj, pa, exc);
4263 if (sig->ret->type == MONO_TYPE_PTR) {
4264 MonoClass *pointer_class;
4265 static MonoMethod *box_method;
4267 MonoObject *box_exc;
4270 * The runtime-invoke wrapper returns a boxed IntPtr, need to
4271 * convert it to a Pointer object.
4273 pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
4275 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4277 g_assert (res->vtable->klass == mono_defaults.int_class);
4278 box_args [0] = ((MonoIntPtr*)res)->m_value;
4279 box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
4280 res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
4281 g_assert (!box_exc);
4284 if (has_byref_nullables) {
4286 * The runtime invoke wrapper already converted byref nullables back,
4287 * and stored them in pa, we just need to copy them back to the
4290 for (i = 0; i < mono_array_length (params); i++) {
4291 MonoType *t = sig->params [i];
4293 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4294 mono_array_setref (params, i, pa [i]);
4303 arith_overflow (void)
4305 mono_raise_exception (mono_get_exception_overflow ());
4310 * @klass: the class of the object that we want to create
4312 * Returns: a newly created object whose definition is
4313 * looked up using @klass. This will not invoke any constructors,
4314 * so the consumer of this routine has to invoke any constructors on
4315 * its own to initialize the object.
4317 * It returns NULL on failure.
4320 mono_object_new (MonoDomain *domain, MonoClass *klass)
4324 vtable = mono_class_vtable (domain, klass);
4327 return mono_object_new_specific (vtable);
4331 * mono_object_new_pinned:
4333 * Same as mono_object_new, but the returned object will be pinned.
4334 * For SGEN, these objects will only be freed at appdomain unload.
4337 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass)
4341 vtable = mono_class_vtable (domain, klass);
4346 return mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
4348 return mono_object_new_specific (vtable);
4353 * mono_object_new_specific:
4354 * @vtable: the vtable of the object that we want to create
4356 * Returns: A newly created object with class and domain specified
4360 mono_object_new_specific (MonoVTable *vtable)
4364 /* check for is_com_object for COM Interop */
4365 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
4368 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4371 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
4374 mono_class_init (klass);
4376 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4378 vtable->domain->create_proxy_for_type_method = im;
4381 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
4383 o = mono_runtime_invoke (im, NULL, pa, NULL);
4384 if (o != NULL) return o;
4387 return mono_object_new_alloc_specific (vtable);
4391 mono_object_new_alloc_specific (MonoVTable *vtable)
4393 MonoObject *o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
4395 if (G_UNLIKELY (vtable->klass->has_finalize))
4396 mono_object_register_finalizer (o);
4402 mono_object_new_fast (MonoVTable *vtable)
4404 return mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
4408 * mono_class_get_allocation_ftn:
4410 * @for_box: the object will be used for boxing
4411 * @pass_size_in_words:
4413 * Return the allocation function appropriate for the given class.
4417 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
4419 *pass_size_in_words = FALSE;
4421 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass) || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4422 return mono_object_new_specific;
4424 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4426 return mono_object_new_fast;
4429 * FIXME: This is actually slower than mono_object_new_fast, because
4430 * of the overhead of parameter passing.
4433 *pass_size_in_words = TRUE;
4434 #ifdef GC_REDIRECT_TO_LOCAL
4435 return GC_local_gcj_fast_malloc;
4437 return GC_gcj_fast_malloc;
4442 return mono_object_new_specific;
4446 * mono_object_new_from_token:
4447 * @image: Context where the type_token is hosted
4448 * @token: a token of the type that we want to create
4450 * Returns: A newly created object whose definition is
4451 * looked up using @token in the @image image
4454 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
4459 class = mono_class_get_checked (image, token, &error);
4460 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
4462 return mono_object_new (domain, class);
4467 * mono_object_clone:
4468 * @obj: the object to clone
4470 * Returns: A newly created object who is a shallow copy of @obj
4473 mono_object_clone (MonoObject *obj)
4476 int size = obj->vtable->klass->instance_size;
4478 if (obj->vtable->klass->rank)
4479 return (MonoObject*)mono_array_clone ((MonoArray*)obj);
4481 o = mono_gc_alloc_obj (obj->vtable, size);
4483 /* If the object doesn't contain references this will do a simple memmove. */
4484 mono_gc_wbarrier_object_copy (o, obj);
4486 if (obj->vtable->klass->has_finalize)
4487 mono_object_register_finalizer (o);
4492 * mono_array_full_copy:
4493 * @src: source array to copy
4494 * @dest: destination array
4496 * Copies the content of one array to another with exactly the same type and size.
4499 mono_array_full_copy (MonoArray *src, MonoArray *dest)
4502 MonoClass *klass = src->obj.vtable->klass;
4504 g_assert (klass == dest->obj.vtable->klass);
4506 size = mono_array_length (src);
4507 g_assert (size == mono_array_length (dest));
4508 size *= mono_array_element_size (klass);
4510 if (klass->element_class->valuetype) {
4511 if (klass->element_class->has_references)
4512 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
4514 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
4516 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
4519 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
4524 * mono_array_clone_in_domain:
4525 * @domain: the domain in which the array will be cloned into
4526 * @array: the array to clone
4528 * This routine returns a copy of the array that is hosted on the
4529 * specified MonoDomain.
4532 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
4537 MonoClass *klass = array->obj.vtable->klass;
4539 if (array->bounds == NULL) {
4540 size = mono_array_length (array);
4541 o = mono_array_new_full (domain, klass, &size, NULL);
4543 size *= mono_array_element_size (klass);
4545 if (klass->element_class->valuetype) {
4546 if (klass->element_class->has_references)
4547 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
4549 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4551 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4554 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4559 sizes = alloca (klass->rank * sizeof(intptr_t) * 2);
4560 size = mono_array_element_size (klass);
4561 for (i = 0; i < klass->rank; ++i) {
4562 sizes [i] = array->bounds [i].length;
4563 size *= array->bounds [i].length;
4564 sizes [i + klass->rank] = array->bounds [i].lower_bound;
4566 o = mono_array_new_full (domain, klass, sizes, (intptr_t*)sizes + klass->rank);
4568 if (klass->element_class->valuetype) {
4569 if (klass->element_class->has_references)
4570 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
4572 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4574 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4577 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4585 * @array: the array to clone
4587 * Returns: A newly created array who is a shallow copy of @array
4590 mono_array_clone (MonoArray *array)
4592 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
4595 /* helper macros to check for overflow when calculating the size of arrays */
4596 #ifdef MONO_BIG_ARRAYS
4597 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
4598 #define MYGUINT_MAX MYGUINT64_MAX
4599 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4600 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
4601 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4602 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
4603 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
4605 #define MYGUINT32_MAX 4294967295U
4606 #define MYGUINT_MAX MYGUINT32_MAX
4607 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4608 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
4609 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4610 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
4611 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
4615 mono_array_calc_byte_len (MonoClass *class, uintptr_t len, uintptr_t *res)
4619 byte_len = mono_array_element_size (class);
4620 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
4623 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
4625 byte_len += sizeof (MonoArray);
4633 * mono_array_new_full:
4634 * @domain: domain where the object is created
4635 * @array_class: array class
4636 * @lengths: lengths for each dimension in the array
4637 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
4639 * This routine creates a new array objects with the given dimensions,
4640 * lower bounds and type.
4643 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
4645 uintptr_t byte_len = 0, len, bounds_size;
4648 MonoArrayBounds *bounds;
4652 if (!array_class->inited)
4653 mono_class_init (array_class);
4657 /* A single dimensional array with a 0 lower bound is the same as an szarray */
4658 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
4660 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
4664 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
4666 for (i = 0; i < array_class->rank; ++i) {
4667 if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
4669 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
4670 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4675 if (!mono_array_calc_byte_len (array_class, len, &byte_len))
4676 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4680 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
4681 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4682 byte_len = (byte_len + 3) & ~3;
4683 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
4684 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4685 byte_len += bounds_size;
4688 * Following three lines almost taken from mono_object_new ():
4689 * they need to be kept in sync.
4691 vtable = mono_class_vtable_full (domain, array_class, TRUE);
4693 o = mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
4695 o = mono_gc_alloc_vector (vtable, byte_len, len);
4696 array = (MonoArray*)o;
4698 bounds = array->bounds;
4701 for (i = 0; i < array_class->rank; ++i) {
4702 bounds [i].length = lengths [i];
4704 bounds [i].lower_bound = lower_bounds [i];
4713 * @domain: domain where the object is created
4714 * @eclass: element class
4715 * @n: number of array elements
4717 * This routine creates a new szarray with @n elements of type @eclass.
4720 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
4724 ac = mono_array_class_get (eclass, 1);
4727 return mono_array_new_specific (mono_class_vtable_full (domain, ac, TRUE), n);
4731 * mono_array_new_specific:
4732 * @vtable: a vtable in the appropriate domain for an initialized class
4733 * @n: number of array elements
4735 * This routine is a fast alternative to mono_array_new() for code which
4736 * can be sure about the domain it operates in.
4739 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
4745 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
4750 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
4751 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4754 o = mono_gc_alloc_vector (vtable, byte_len, n);
4761 * mono_string_new_utf16:
4762 * @text: a pointer to an utf16 string
4763 * @len: the length of the string
4765 * Returns: A newly created string object which contains @text.
4768 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
4772 s = mono_string_new_size (domain, len);
4773 g_assert (s != NULL);
4775 memcpy (mono_string_chars (s), text, len * 2);
4781 * mono_string_new_utf32:
4782 * @text: a pointer to an utf32 string
4783 * @len: the length of the string
4785 * Returns: A newly created string object which contains @text.
4788 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
4791 mono_unichar2 *utf16_output = NULL;
4792 gint32 utf16_len = 0;
4793 GError *error = NULL;
4794 glong items_written;
4796 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &error);
4799 g_error_free (error);
4801 while (utf16_output [utf16_len]) utf16_len++;
4803 s = mono_string_new_size (domain, utf16_len);
4804 g_assert (s != NULL);
4806 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
4808 g_free (utf16_output);
4814 * mono_string_new_size:
4815 * @text: a pointer to an utf16 string
4816 * @len: the length of the string
4818 * Returns: A newly created string object of @len
4821 mono_string_new_size (MonoDomain *domain, gint32 len)
4827 /* check for overflow */
4828 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2))
4829 mono_gc_out_of_memory (-1);
4831 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
4832 g_assert (size > 0);
4834 vtable = mono_class_vtable (domain, mono_defaults.string_class);
4837 s = mono_gc_alloc_string (vtable, size, len);
4843 * mono_string_new_len:
4844 * @text: a pointer to an utf8 string
4845 * @length: number of bytes in @text to consider
4847 * Returns: A newly created string object which contains @text.
4850 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
4852 GError *error = NULL;
4853 MonoString *o = NULL;
4855 glong items_written;
4857 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &error);
4860 o = mono_string_new_utf16 (domain, ut, items_written);
4862 g_error_free (error);
4871 * @text: a pointer to an utf8 string
4873 * Returns: A newly created string object which contains @text.
4876 mono_string_new (MonoDomain *domain, const char *text)
4878 GError *error = NULL;
4879 MonoString *o = NULL;
4881 glong items_written;
4886 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
4889 o = mono_string_new_utf16 (domain, ut, items_written);
4891 g_error_free (error);
4894 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
4899 MonoString *o = NULL;
4901 if (!g_utf8_validate (text, -1, &end))
4904 len = g_utf8_strlen (text, -1);
4905 o = mono_string_new_size (domain, len);
4906 str = mono_string_chars (o);
4908 while (text < end) {
4909 *str++ = g_utf8_get_char (text);
4910 text = g_utf8_next_char (text);
4917 * mono_string_new_wrapper:
4918 * @text: pointer to utf8 characters.
4920 * Helper function to create a string object from @text in the current domain.
4923 mono_string_new_wrapper (const char *text)
4925 MonoDomain *domain = mono_domain_get ();
4928 return mono_string_new (domain, text);
4935 * @class: the class of the value
4936 * @value: a pointer to the unboxed data
4938 * Returns: A newly created object which contains @value.
4941 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
4947 g_assert (class->valuetype);
4948 if (mono_class_is_nullable (class))
4949 return mono_nullable_box (value, class);
4951 vtable = mono_class_vtable (domain, class);
4954 size = mono_class_instance_size (class);
4955 res = mono_object_new_alloc_specific (vtable);
4957 size = size - sizeof (MonoObject);
4960 g_assert (size == mono_class_value_size (class, NULL));
4961 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
4963 #if NO_UNALIGNED_ACCESS
4964 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
4968 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
4971 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
4974 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
4977 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
4980 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
4984 if (class->has_finalize)
4985 mono_object_register_finalizer (res);
4991 * @dest: destination pointer
4992 * @src: source pointer
4993 * @klass: a valuetype class
4995 * Copy a valuetype from @src to @dest. This function must be used
4996 * when @klass contains references fields.
4999 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
5001 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
5005 * mono_value_copy_array:
5006 * @dest: destination array
5007 * @dest_idx: index in the @dest array
5008 * @src: source pointer
5009 * @count: number of items
5011 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
5012 * This function must be used when @klass contains references fields.
5013 * Overlap is handled.
5016 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
5018 int size = mono_array_element_size (dest->obj.vtable->klass);
5019 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
5020 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
5021 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
5025 * mono_object_get_domain:
5026 * @obj: object to query
5028 * Returns: the MonoDomain where the object is hosted
5031 mono_object_get_domain (MonoObject *obj)
5033 return mono_object_domain (obj);
5037 * mono_object_get_class:
5038 * @obj: object to query
5040 * Returns: the MonOClass of the object.
5043 mono_object_get_class (MonoObject *obj)
5045 return mono_object_class (obj);
5048 * mono_object_get_size:
5049 * @o: object to query
5051 * Returns: the size, in bytes, of @o
5054 mono_object_get_size (MonoObject* o)
5056 MonoClass* klass = mono_object_class (o);
5057 if (klass == mono_defaults.string_class) {
5058 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
5059 } else if (o->vtable->rank) {
5060 MonoArray *array = (MonoArray*)o;
5061 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
5062 if (array->bounds) {
5065 size += sizeof (MonoArrayBounds) * o->vtable->rank;
5069 return mono_class_instance_size (klass);
5074 * mono_object_unbox:
5075 * @obj: object to unbox
5077 * Returns: a pointer to the start of the valuetype boxed in this
5080 * This method will assert if the object passed is not a valuetype.
5083 mono_object_unbox (MonoObject *obj)
5085 /* add assert for valuetypes? */
5086 g_assert (obj->vtable->klass->valuetype);
5087 return ((char*)obj) + sizeof (MonoObject);
5091 * mono_object_isinst:
5093 * @klass: a pointer to a class
5095 * Returns: @obj if @obj is derived from @klass
5098 mono_object_isinst (MonoObject *obj, MonoClass *klass)
5101 mono_class_init (klass);
5103 if (mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
5104 return mono_object_isinst_mbyref (obj, klass);
5109 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
5113 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
5122 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5123 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
5127 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
5128 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
5131 MonoClass *oklass = vt->klass;
5132 if (mono_class_is_transparent_proxy (oklass))
5133 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
5135 mono_class_setup_supertypes (klass);
5136 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
5139 #ifndef DISABLE_REMOTING
5140 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
5142 MonoDomain *domain = mono_domain_get ();
5144 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
5145 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
5146 MonoMethod *im = NULL;
5149 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
5150 im = mono_object_get_virtual_method (rp, im);
5153 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
5156 res = mono_runtime_invoke (im, rp, pa, NULL);
5158 if (*(MonoBoolean *) mono_object_unbox(res)) {
5159 /* Update the vtable of the remote type, so it can safely cast to this new type */
5160 mono_upgrade_remote_class (domain, obj, klass);
5164 #endif /* DISABLE_REMOTING */
5169 * mono_object_castclass_mbyref:
5171 * @klass: a pointer to a class
5173 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
5176 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
5178 if (!obj) return NULL;
5179 if (mono_object_isinst_mbyref (obj, klass)) return obj;
5181 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
5183 "InvalidCastException"));
5188 MonoDomain *orig_domain;
5194 str_lookup (MonoDomain *domain, gpointer user_data)
5196 LDStrInfo *info = user_data;
5197 if (info->res || domain == info->orig_domain)
5199 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
5205 mono_string_get_pinned (MonoString *str)
5209 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
5210 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
5212 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
5213 news->length = mono_string_length (str);
5219 #define mono_string_get_pinned(str) (str)
5223 mono_string_is_interned_lookup (MonoString *str, int insert)
5225 MonoGHashTable *ldstr_table;
5226 MonoString *s, *res;
5229 domain = ((MonoObject *)str)->vtable->domain;
5230 ldstr_table = domain->ldstr_table;
5232 res = mono_g_hash_table_lookup (ldstr_table, str);
5238 /* Allocate outside the lock */
5240 s = mono_string_get_pinned (str);
5243 res = mono_g_hash_table_lookup (ldstr_table, str);
5248 mono_g_hash_table_insert (ldstr_table, s, s);
5253 LDStrInfo ldstr_info;
5254 ldstr_info.orig_domain = domain;
5255 ldstr_info.ins = str;
5256 ldstr_info.res = NULL;
5258 mono_domain_foreach (str_lookup, &ldstr_info);
5259 if (ldstr_info.res) {
5261 * the string was already interned in some other domain:
5262 * intern it in the current one as well.
5264 mono_g_hash_table_insert (ldstr_table, str, str);
5274 * mono_string_is_interned:
5275 * @o: String to probe
5277 * Returns whether the string has been interned.
5280 mono_string_is_interned (MonoString *o)
5282 return mono_string_is_interned_lookup (o, FALSE);
5286 * mono_string_intern:
5287 * @o: String to intern
5289 * Interns the string passed.
5290 * Returns: The interned string.
5293 mono_string_intern (MonoString *str)
5295 return mono_string_is_interned_lookup (str, TRUE);
5300 * @domain: the domain where the string will be used.
5301 * @image: a metadata context
5302 * @idx: index into the user string table.
5304 * Implementation for the ldstr opcode.
5305 * Returns: a loaded string from the @image/@idx combination.
5308 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
5310 if (image->dynamic) {
5311 MonoString *str = mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
5314 if (!mono_verifier_verify_string_signature (image, idx, NULL))
5315 return NULL; /*FIXME we should probably be raising an exception here*/
5316 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
5321 * mono_ldstr_metadata_sig
5322 * @domain: the domain for the string
5323 * @sig: the signature of a metadata string
5325 * Returns: a MonoString for a string stored in the metadata
5328 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
5330 const char *str = sig;
5331 MonoString *o, *interned;
5334 len2 = mono_metadata_decode_blob_size (str, &str);
5337 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
5338 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
5341 guint16 *p2 = (guint16*)mono_string_chars (o);
5342 for (i = 0; i < len2; ++i) {
5343 *p2 = GUINT16_FROM_LE (*p2);
5349 interned = mono_g_hash_table_lookup (domain->ldstr_table, o);
5352 return interned; /* o will get garbage collected */
5354 o = mono_string_get_pinned (o);
5357 interned = mono_g_hash_table_lookup (domain->ldstr_table, o);
5359 mono_g_hash_table_insert (domain->ldstr_table, o, o);
5369 * mono_string_to_utf8:
5370 * @s: a System.String
5372 * Returns the UTF8 representation for @s.
5373 * The resulting buffer needs to be freed with mono_free().
5375 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
5378 mono_string_to_utf8 (MonoString *s)
5381 char *result = mono_string_to_utf8_checked (s, &error);
5383 if (!mono_error_ok (&error))
5384 mono_error_raise_exception (&error);
5389 * mono_string_to_utf8_checked:
5390 * @s: a System.String
5391 * @error: a MonoError.
5393 * Converts a MonoString to its UTF8 representation. May fail; check
5394 * @error to determine whether the conversion was successful.
5395 * The resulting buffer should be freed with mono_free().
5398 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
5402 GError *gerror = NULL;
5404 mono_error_init (error);
5410 return g_strdup ("");
5412 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
5414 mono_error_set_argument (error, "string", "%s", gerror->message);
5415 g_error_free (gerror);
5418 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5419 if (s->length > written) {
5420 /* allocate the total length and copy the part of the string that has been converted */
5421 char *as2 = g_malloc0 (s->length);
5422 memcpy (as2, as, written);
5431 * mono_string_to_utf8_ignore:
5434 * Converts a MonoString to its UTF8 representation. Will ignore
5435 * invalid surrogate pairs.
5436 * The resulting buffer should be freed with mono_free().
5440 mono_string_to_utf8_ignore (MonoString *s)
5449 return g_strdup ("");
5451 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
5453 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5454 if (s->length > written) {
5455 /* allocate the total length and copy the part of the string that has been converted */
5456 char *as2 = g_malloc0 (s->length);
5457 memcpy (as2, as, written);
5466 * mono_string_to_utf8_image_ignore:
5467 * @s: a System.String
5469 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
5472 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
5474 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
5478 * mono_string_to_utf8_mp_ignore:
5479 * @s: a System.String
5481 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
5484 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
5486 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
5491 * mono_string_to_utf16:
5494 * Return an null-terminated array of the utf-16 chars
5495 * contained in @s. The result must be freed with g_free().
5496 * This is a temporary helper until our string implementation
5497 * is reworked to always include the null terminating char.
5500 mono_string_to_utf16 (MonoString *s)
5507 as = g_malloc ((s->length * 2) + 2);
5508 as [(s->length * 2)] = '\0';
5509 as [(s->length * 2) + 1] = '\0';
5512 return (gunichar2 *)(as);
5515 memcpy (as, mono_string_chars(s), s->length * 2);
5516 return (gunichar2 *)(as);
5520 * mono_string_to_utf32:
5523 * Return an null-terminated array of the UTF-32 (UCS-4) chars
5524 * contained in @s. The result must be freed with g_free().
5527 mono_string_to_utf32 (MonoString *s)
5529 mono_unichar4 *utf32_output = NULL;
5530 GError *error = NULL;
5531 glong items_written;
5536 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
5539 g_error_free (error);
5541 return utf32_output;
5545 * mono_string_from_utf16:
5546 * @data: the UTF16 string (LPWSTR) to convert
5548 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
5550 * Returns: a MonoString.
5553 mono_string_from_utf16 (gunichar2 *data)
5555 MonoDomain *domain = mono_domain_get ();
5561 while (data [len]) len++;
5563 return mono_string_new_utf16 (domain, data, len);
5567 * mono_string_from_utf32:
5568 * @data: the UTF32 string (LPWSTR) to convert
5570 * Converts a UTF32 (UCS-4)to a MonoString.
5572 * Returns: a MonoString.
5575 mono_string_from_utf32 (mono_unichar4 *data)
5577 MonoString* result = NULL;
5578 mono_unichar2 *utf16_output = NULL;
5579 GError *error = NULL;
5580 glong items_written;
5586 while (data [len]) len++;
5588 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &error);
5591 g_error_free (error);
5593 result = mono_string_from_utf16 (utf16_output);
5594 g_free (utf16_output);
5599 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
5606 r = mono_string_to_utf8_ignore (s);
5608 r = mono_string_to_utf8_checked (s, error);
5609 if (!mono_error_ok (error))
5616 len = strlen (r) + 1;
5618 mp_s = mono_mempool_alloc (mp, len);
5620 mp_s = mono_image_alloc (image, len);
5622 memcpy (mp_s, r, len);
5630 * mono_string_to_utf8_image:
5631 * @s: a System.String
5633 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
5636 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
5638 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
5642 * mono_string_to_utf8_mp:
5643 * @s: a System.String
5645 * Same as mono_string_to_utf8, but allocate the string from a mempool.
5648 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
5650 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
5654 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
5657 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
5659 eh_callbacks = *cbs;
5662 MonoRuntimeExceptionHandlingCallbacks *
5663 mono_get_eh_callbacks (void)
5665 return &eh_callbacks;
5669 * mono_raise_exception:
5670 * @ex: exception object
5672 * Signal the runtime that the exception @ex has been raised in unmanaged code.
5675 mono_raise_exception (MonoException *ex)
5678 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
5679 * that will cause gcc to omit the function epilog, causing problems when
5680 * the JIT tries to walk the stack, since the return address on the stack
5681 * will point into the next function in the executable, not this one.
5683 eh_callbacks.mono_raise_exception (ex);
5687 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
5689 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
5693 * mono_wait_handle_new:
5694 * @domain: Domain where the object will be created
5695 * @handle: Handle for the wait handle
5697 * Returns: A new MonoWaitHandle created in the given domain for the given handle
5700 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
5702 MonoWaitHandle *res;
5703 gpointer params [1];
5704 static MonoMethod *handle_set;
5706 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.manualresetevent_class);
5708 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
5710 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
5712 params [0] = &handle;
5713 mono_runtime_invoke (handle_set, res, params, NULL);
5719 mono_wait_handle_get_handle (MonoWaitHandle *handle)
5721 static MonoClassField *f_os_handle;
5722 static MonoClassField *f_safe_handle;
5724 if (!f_os_handle && !f_safe_handle) {
5725 f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
5726 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
5731 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
5735 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
5742 mono_runtime_capture_context (MonoDomain *domain)
5744 RuntimeInvokeFunction runtime_invoke;
5746 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
5747 MonoMethod *method = mono_get_context_capture_method ();
5748 MonoMethod *wrapper;
5751 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
5752 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
5753 domain->capture_context_method = mono_compile_method (method);
5756 runtime_invoke = domain->capture_context_runtime_invoke;
5758 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
5761 * mono_async_result_new:
5762 * @domain:domain where the object will be created.
5763 * @handle: wait handle.
5764 * @state: state to pass to AsyncResult
5765 * @data: C closure data.
5767 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
5768 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
5772 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
5774 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
5775 MonoObject *context = mono_runtime_capture_context (domain);
5776 /* we must capture the execution context from the original thread */
5778 MONO_OBJECT_SETREF (res, execution_context, context);
5779 /* note: result may be null if the flow is suppressed */
5783 MONO_OBJECT_SETREF (res, object_data, object_data);
5784 MONO_OBJECT_SETREF (res, async_state, state);
5786 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
5788 res->sync_completed = FALSE;
5789 res->completed = FALSE;
5795 mono_async_result_invoke (MonoAsyncResult *ares, MonoObject **exc)
5799 MonoInternalThread *thread;
5802 g_assert (ares->async_delegate);
5804 thread = mono_thread_internal_current ();
5806 ac = (MonoAsyncCall*) ares->object_data;
5808 thread->async_invoke_method = ((MonoDelegate*) ares->async_delegate)->method;
5809 res = mono_runtime_delegate_invoke (ares->async_delegate, (void**) &ares->async_state, exc);
5810 thread->async_invoke_method = NULL;
5812 MonoArray *out_args = NULL;
5813 gpointer wait_event = NULL;
5815 ac->msg->exc = NULL;
5816 res = mono_message_invoke (ares->async_delegate, ac->msg, exc, &out_args);
5817 MONO_OBJECT_SETREF (ac->msg, exc, *exc);
5818 MONO_OBJECT_SETREF (ac, res, res);
5819 MONO_OBJECT_SETREF (ac, out_args, out_args);
5821 mono_monitor_enter ((MonoObject*) ares);
5822 ares->completed = 1;
5824 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
5825 mono_monitor_exit ((MonoObject*) ares);
5827 if (wait_event != NULL)
5828 SetEvent (wait_event);
5830 if (!ac->cb_method) {
5833 thread->async_invoke_method = ac->cb_method;
5834 mono_runtime_invoke (ac->cb_method, ac->cb_target, (gpointer*) &ares, exc);
5835 thread->async_invoke_method = NULL;
5843 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *this)
5845 MonoObject *exc = NULL;
5846 MonoObject *res = mono_async_result_invoke (this, &exc);
5848 mono_raise_exception ((MonoException*) exc);
5853 mono_message_init (MonoDomain *domain,
5854 MonoMethodMessage *this,
5855 MonoReflectionMethod *method,
5856 MonoArray *out_args)
5858 static MonoClass *object_array_klass;
5859 static MonoClass *byte_array_klass;
5860 static MonoClass *string_array_klass;
5861 MonoMethodSignature *sig = mono_method_signature (method->method);
5867 if (!object_array_klass) {
5870 klass = mono_array_class_get (mono_defaults.byte_class, 1);
5872 byte_array_klass = klass;
5874 klass = mono_array_class_get (mono_defaults.string_class, 1);
5876 string_array_klass = klass;
5878 klass = mono_array_class_get (mono_defaults.object_class, 1);
5881 mono_atomic_store_release (&object_array_klass, klass);
5884 MONO_OBJECT_SETREF (this, method, method);
5886 MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
5887 MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
5888 this->async_result = NULL;
5889 this->call_type = CallType_Sync;
5891 names = g_new (char *, sig->param_count);
5892 mono_method_get_param_names (method->method, (const char **) names);
5893 MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
5895 for (i = 0; i < sig->param_count; i++) {
5896 name = mono_string_new (domain, names [i]);
5897 mono_array_setref (this->names, i, name);
5901 for (i = 0, j = 0; i < sig->param_count; i++) {
5902 if (sig->params [i]->byref) {
5904 MonoObject* arg = mono_array_get (out_args, gpointer, j);
5905 mono_array_setref (this->args, i, arg);
5909 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
5913 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
5916 mono_array_set (this->arg_types, guint8, i, arg_type);
5920 #ifndef DISABLE_REMOTING
5922 * mono_remoting_invoke:
5923 * @real_proxy: pointer to a RealProxy object
5924 * @msg: The MonoMethodMessage to execute
5925 * @exc: used to store exceptions
5926 * @out_args: used to store output arguments
5928 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
5929 * IMessage interface and it is not trivial to extract results from there. So
5930 * we call an helper method PrivateInvoke instead of calling
5931 * RealProxy::Invoke() directly.
5933 * Returns: the result object.
5936 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
5937 MonoObject **exc, MonoArray **out_args)
5939 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
5942 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
5945 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
5947 real_proxy->vtable->domain->private_invoke_method = im;
5950 pa [0] = real_proxy;
5955 return mono_runtime_invoke (im, NULL, pa, exc);
5960 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
5961 MonoObject **exc, MonoArray **out_args)
5963 static MonoClass *object_array_klass;
5966 MonoMethodSignature *sig;
5968 int i, j, outarg_count = 0;
5970 #ifndef DISABLE_REMOTING
5971 if (target && mono_object_is_transparent_proxy (target)) {
5972 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
5973 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
5974 target = tp->rp->unwrapped_server;
5976 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
5981 domain = mono_domain_get ();
5982 method = msg->method->method;
5983 sig = mono_method_signature (method);
5985 for (i = 0; i < sig->param_count; i++) {
5986 if (sig->params [i]->byref)
5990 if (!object_array_klass) {
5993 klass = mono_array_class_get (mono_defaults.object_class, 1);
5996 mono_memory_barrier ();
5997 object_array_klass = klass;
6000 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
6001 *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
6004 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
6006 for (i = 0, j = 0; i < sig->param_count; i++) {
6007 if (sig->params [i]->byref) {
6009 arg = mono_array_get (msg->args, gpointer, i);
6010 mono_array_setref (*out_args, j, arg);
6019 * mono_object_to_string:
6021 * @exc: Any exception thrown by ToString (). May be NULL.
6023 * Returns: the result of calling ToString () on an object.
6026 mono_object_to_string (MonoObject *obj, MonoObject **exc)
6028 static MonoMethod *to_string = NULL;
6035 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
6037 method = mono_object_get_virtual_method (obj, to_string);
6039 // Unbox value type if needed
6040 if (mono_class_is_valuetype (mono_method_get_class (method))) {
6041 target = mono_object_unbox (obj);
6044 return (MonoString *) mono_runtime_invoke (method, target, NULL, exc);
6048 * mono_print_unhandled_exception:
6049 * @exc: The exception
6051 * Prints the unhandled exception.
6054 mono_print_unhandled_exception (MonoObject *exc)
6057 char *message = (char*)"";
6058 gboolean free_message = FALSE;
6061 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
6062 message = g_strdup ("OutOfMemoryException");
6063 free_message = TRUE;
6064 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
6065 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
6066 free_message = TRUE;
6069 if (((MonoException*)exc)->native_trace_ips) {
6070 message = mono_exception_get_native_backtrace ((MonoException*)exc);
6071 free_message = TRUE;
6073 MonoObject *other_exc = NULL;
6074 str = mono_object_to_string (exc, &other_exc);
6076 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
6077 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
6079 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
6080 original_backtrace, nested_backtrace);
6082 g_free (original_backtrace);
6083 g_free (nested_backtrace);
6084 free_message = TRUE;
6086 message = mono_string_to_utf8_checked (str, &error);
6087 if (!mono_error_ok (&error)) {
6088 mono_error_cleanup (&error);
6089 message = (char *) "";
6091 free_message = TRUE;
6098 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
6099 * exc->vtable->klass->name, message);
6101 g_printerr ("\nUnhandled Exception:\n%s\n", message);
6108 * mono_delegate_ctor:
6109 * @this: pointer to an uninitialized delegate object
6110 * @target: target object
6111 * @addr: pointer to native code
6114 * Initialize a delegate and sets a specific method, not the one
6115 * associated with addr. This is useful when sharing generic code.
6116 * In that case addr will most probably not be associated with the
6117 * correct instantiation of the method.
6120 mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer addr, MonoMethod *method)
6122 MonoDelegate *delegate = (MonoDelegate *)this;
6127 g_assert (mono_class_has_parent (mono_object_class (this), mono_defaults.multicastdelegate_class));
6130 delegate->method = method;
6132 mono_stats.delegate_creations++;
6134 #ifndef DISABLE_REMOTING
6135 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
6137 method = mono_marshal_get_remoting_invoke (method);
6138 delegate->method_ptr = mono_compile_method (method);
6139 MONO_OBJECT_SETREF (delegate, target, target);
6143 delegate->method_ptr = addr;
6144 MONO_OBJECT_SETREF (delegate, target, target);
6147 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
6151 * mono_delegate_ctor:
6152 * @this: pointer to an uninitialized delegate object
6153 * @target: target object
6154 * @addr: pointer to native code
6156 * This is used to initialize a delegate.
6159 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
6161 MonoDomain *domain = mono_domain_get ();
6163 MonoMethod *method = NULL;
6167 ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr));
6169 if (!ji && domain != mono_get_root_domain ())
6170 ji = mono_jit_info_table_find (mono_get_root_domain (), mono_get_addr_from_ftnptr (addr));
6172 method = mono_jit_info_get_method (ji);
6173 g_assert (!method->klass->generic_container);
6176 mono_delegate_ctor_with_method (this, target, addr, method);
6180 * mono_method_call_message_new:
6181 * @method: method to encapsulate
6182 * @params: parameters to the method
6183 * @invoke: optional, delegate invoke.
6184 * @cb: async callback delegate.
6185 * @state: state passed to the async callback.
6187 * Translates arguments pointers into a MonoMethodMessage.
6190 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
6191 MonoDelegate **cb, MonoObject **state)
6193 MonoDomain *domain = mono_domain_get ();
6194 MonoMethodSignature *sig = mono_method_signature (method);
6195 MonoMethodMessage *msg;
6198 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6201 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
6202 count = sig->param_count - 2;
6204 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
6205 count = sig->param_count;
6208 for (i = 0; i < count; i++) {
6213 if (sig->params [i]->byref)
6214 vpos = *((gpointer *)params [i]);
6218 class = mono_class_from_mono_type (sig->params [i]);
6220 if (class->valuetype)
6221 arg = mono_value_box (domain, class, vpos);
6223 arg = *((MonoObject **)vpos);
6225 mono_array_setref (msg->args, i, arg);
6228 if (cb != NULL && state != NULL) {
6229 *cb = *((MonoDelegate **)params [i]);
6231 *state = *((MonoObject **)params [i]);
6238 * mono_method_return_message_restore:
6240 * Restore results from message based processing back to arguments pointers
6243 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
6245 MonoMethodSignature *sig = mono_method_signature (method);
6246 int i, j, type, size, out_len;
6248 if (out_args == NULL)
6250 out_len = mono_array_length (out_args);
6254 for (i = 0, j = 0; i < sig->param_count; i++) {
6255 MonoType *pt = sig->params [i];
6260 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
6262 arg = mono_array_get (out_args, gpointer, j);
6265 g_assert (type != MONO_TYPE_VOID);
6267 if (MONO_TYPE_IS_REFERENCE (pt)) {
6268 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
6271 MonoClass *class = ((MonoObject*)arg)->vtable->klass;
6272 size = mono_class_value_size (class, NULL);
6273 if (class->has_references)
6274 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, class);
6276 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
6278 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
6279 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
6288 #ifndef DISABLE_REMOTING
6291 * mono_load_remote_field:
6292 * @this: pointer to an object
6293 * @klass: klass of the object containing @field
6294 * @field: the field to load
6295 * @res: a storage to store the result
6297 * This method is called by the runtime on attempts to load fields of
6298 * transparent proxy objects. @this points to such TP, @klass is the class of
6299 * the object containing @field. @res is a storage location which can be
6300 * used to store the result.
6302 * Returns: an address pointing to the value of field.
6305 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
6307 static MonoMethod *getter = NULL;
6308 MonoDomain *domain = mono_domain_get ();
6309 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6310 MonoClass *field_class;
6311 MonoMethodMessage *msg;
6312 MonoArray *out_args;
6316 g_assert (mono_object_is_transparent_proxy (this));
6317 g_assert (res != NULL);
6319 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6320 mono_field_get_value (tp->rp->unwrapped_server, field, res);
6325 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6329 field_class = mono_class_from_mono_type (field->type);
6331 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6332 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6333 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6335 full_name = mono_type_get_full_name (klass);
6336 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6337 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6340 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6342 if (exc) mono_raise_exception ((MonoException *)exc);
6344 if (mono_array_length (out_args) == 0)
6347 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
6349 if (field_class->valuetype) {
6350 return ((char *)*res) + sizeof (MonoObject);
6356 * mono_load_remote_field_new:
6361 * Missing documentation.
6364 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
6366 static MonoMethod *getter = NULL;
6367 MonoDomain *domain = mono_domain_get ();
6368 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6369 MonoClass *field_class;
6370 MonoMethodMessage *msg;
6371 MonoArray *out_args;
6372 MonoObject *exc, *res;
6375 g_assert (mono_object_is_transparent_proxy (this));
6377 field_class = mono_class_from_mono_type (field->type);
6379 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6381 if (field_class->valuetype) {
6382 res = mono_object_new (domain, field_class);
6383 val = ((gchar *) res) + sizeof (MonoObject);
6387 mono_field_get_value (tp->rp->unwrapped_server, field, val);
6392 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6396 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6397 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6399 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6401 full_name = mono_type_get_full_name (klass);
6402 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6403 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6406 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6408 if (exc) mono_raise_exception ((MonoException *)exc);
6410 if (mono_array_length (out_args) == 0)
6413 res = mono_array_get (out_args, MonoObject *, 0);
6419 * mono_store_remote_field:
6420 * @this: pointer to an object
6421 * @klass: klass of the object containing @field
6422 * @field: the field to load
6423 * @val: the value/object to store
6425 * This method is called by the runtime on attempts to store fields of
6426 * transparent proxy objects. @this points to such TP, @klass is the class of
6427 * the object containing @field. @val is the new value to store in @field.
6430 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
6432 static MonoMethod *setter = NULL;
6433 MonoDomain *domain = mono_domain_get ();
6434 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6435 MonoClass *field_class;
6436 MonoMethodMessage *msg;
6437 MonoArray *out_args;
6442 g_assert (mono_object_is_transparent_proxy (this));
6444 field_class = mono_class_from_mono_type (field->type);
6446 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6447 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
6448 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
6453 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6457 if (field_class->valuetype)
6458 arg = mono_value_box (domain, field_class, val);
6460 arg = *((MonoObject **)val);
6463 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6464 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6466 full_name = mono_type_get_full_name (klass);
6467 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6468 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6469 mono_array_setref (msg->args, 2, arg);
6472 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6474 if (exc) mono_raise_exception ((MonoException *)exc);
6478 * mono_store_remote_field_new:
6484 * Missing documentation
6487 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
6489 static MonoMethod *setter = NULL;
6490 MonoDomain *domain = mono_domain_get ();
6491 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6492 MonoClass *field_class;
6493 MonoMethodMessage *msg;
6494 MonoArray *out_args;
6498 g_assert (mono_object_is_transparent_proxy (this));
6500 field_class = mono_class_from_mono_type (field->type);
6502 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6503 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
6504 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
6509 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6513 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6514 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6516 full_name = mono_type_get_full_name (klass);
6517 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6518 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6519 mono_array_setref (msg->args, 2, arg);
6522 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6524 if (exc) mono_raise_exception ((MonoException *)exc);
6529 * mono_create_ftnptr:
6531 * Given a function address, create a function descriptor for it.
6532 * This is only needed on some platforms.
6535 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
6537 return callbacks.create_ftnptr (domain, addr);
6541 * mono_get_addr_from_ftnptr:
6543 * Given a pointer to a function descriptor, return the function address.
6544 * This is only needed on some platforms.
6547 mono_get_addr_from_ftnptr (gpointer descr)
6549 return callbacks.get_addr_from_ftnptr (descr);
6553 * mono_string_chars:
6556 * Returns a pointer to the UCS16 characters stored in the MonoString
6559 mono_string_chars (MonoString *s)
6565 * mono_string_length:
6568 * Returns the lenght in characters of the string
6571 mono_string_length (MonoString *s)
6577 * mono_array_length:
6578 * @array: a MonoArray*
6580 * Returns the total number of elements in the array. This works for
6581 * both vectors and multidimensional arrays.
6584 mono_array_length (MonoArray *array)
6586 return array->max_length;
6590 * mono_array_addr_with_size:
6591 * @array: a MonoArray*
6592 * @size: size of the array elements
6593 * @idx: index into the array
6595 * Returns the address of the @idx element in the array.
6598 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
6600 return ((char*)(array)->vector) + size * idx;