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-2009 Novell, Inc (http://www.novell.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/utils/strenc.h>
42 #include <mono/utils/mono-counters.h>
45 #define NEED_TO_ZERO_PTRFREE 1
46 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = GC_MALLOC_ATOMIC ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
47 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = GC_MALLOC ((size)); (obj)->vtable = (vt);} while (0)
48 #ifdef HAVE_GC_GCJ_MALLOC
49 #define GC_NO_DESCRIPTOR ((gpointer)(0 | GC_DS_LENGTH))
50 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_GCJ_MALLOC ((size),(type)); } while (0)
52 #define GC_NO_DESCRIPTOR (NULL)
53 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_MALLOC ((size)); *(gpointer*)dest = (type);} while (0)
57 #define GC_NO_DESCRIPTOR (NULL)
58 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
59 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
60 #define ALLOC_TYPED(dest,size,type) do { (dest) = mono_gc_alloc_obj (type, size);} while (0)
62 #define NEED_TO_ZERO_PTRFREE 1
63 #define GC_NO_DESCRIPTOR (NULL)
64 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = malloc ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
65 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = calloc (1, (size)); (obj)->vtable = (vt);} while (0)
66 #define ALLOC_TYPED(dest,size,type) do { (dest) = calloc (1, (size)); *(gpointer*)dest = (type);} while (0)
70 static MonoObject* mono_object_new_ptrfree (MonoVTable *vtable);
71 static MonoObject* mono_object_new_ptrfree_box (MonoVTable *vtable);
74 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value);
77 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig);
79 #define ldstr_lock() EnterCriticalSection (&ldstr_section)
80 #define ldstr_unlock() LeaveCriticalSection (&ldstr_section)
81 static CRITICAL_SECTION ldstr_section;
83 static gboolean profile_allocs = TRUE;
86 mono_runtime_object_init (MonoObject *this)
88 MonoMethod *method = NULL;
89 MonoClass *klass = this->vtable->klass;
91 method = mono_class_get_method_from_name (klass, ".ctor", 0);
94 if (method->klass->valuetype)
95 this = mono_object_unbox (this);
96 mono_runtime_invoke (method, this, NULL, NULL);
99 /* The pseudo algorithm for type initialization from the spec
100 Note it doesn't say anything about domains - only threads.
102 2. If the type is initialized you are done.
103 2.1. If the type is not yet initialized, try to take an
105 2.2. If successful, record this thread as responsible for
106 initializing the type and proceed to step 2.3.
107 2.2.1. If not, see whether this thread or any thread
108 waiting for this thread to complete already holds the lock.
109 2.2.2. If so, return since blocking would create a deadlock. This thread
110 will now see an incompletely initialized state for the type,
111 but no deadlock will arise.
112 2.2.3 If not, block until the type is initialized then return.
113 2.3 Initialize the parent type and then all interfaces implemented
115 2.4 Execute the type initialization code for this type.
116 2.5 Mark the type as initialized, release the initialization lock,
117 awaken any threads waiting for this type to be initialized,
124 guint32 initializing_tid;
125 guint32 waiting_count;
127 CRITICAL_SECTION initialization_section;
128 } TypeInitializationLock;
130 /* for locking access to type_initialization_hash and blocked_thread_hash */
131 #define mono_type_initialization_lock() EnterCriticalSection (&type_initialization_section)
132 #define mono_type_initialization_unlock() LeaveCriticalSection (&type_initialization_section)
133 static CRITICAL_SECTION type_initialization_section;
135 /* from vtable to lock */
136 static GHashTable *type_initialization_hash;
138 /* from thread id to thread id being waited on */
139 static GHashTable *blocked_thread_hash;
142 static MonoThread *main_thread;
145 * mono_thread_set_main:
146 * @thread: thread to set as the main thread
148 * This function can be used to instruct the runtime to treat @thread
149 * as the main thread, ie, the thread that would normally execute the Main()
150 * method. This basically means that at the end of @thread, the runtime will
151 * wait for the existing foreground threads to quit and other such details.
154 mono_thread_set_main (MonoThread *thread)
156 main_thread = thread;
160 mono_thread_get_main (void)
166 mono_type_initialization_init (void)
168 InitializeCriticalSection (&type_initialization_section);
169 type_initialization_hash = g_hash_table_new (NULL, NULL);
170 blocked_thread_hash = g_hash_table_new (NULL, NULL);
171 InitializeCriticalSection (&ldstr_section);
175 mono_type_initialization_cleanup (void)
178 /* This is causing race conditions with
179 * mono_release_type_locks
181 DeleteCriticalSection (&type_initialization_section);
183 DeleteCriticalSection (&ldstr_section);
187 * get_type_init_exception_for_vtable:
189 * Return the stored type initialization exception for VTABLE.
191 static MonoException*
192 get_type_init_exception_for_vtable (MonoVTable *vtable)
194 MonoDomain *domain = vtable->domain;
195 MonoClass *klass = vtable->klass;
199 g_assert (vtable->init_failed);
202 * If the initializing thread was rudely aborted, the exception is not stored
206 mono_domain_lock (domain);
207 if (domain->type_init_exception_hash)
208 ex = mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
209 mono_domain_unlock (domain);
212 if (klass->name_space && *klass->name_space)
213 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
215 full_name = g_strdup (klass->name);
216 ex = mono_get_exception_type_initialization (full_name, NULL);
223 * mono_runtime_class_init:
224 * @vtable: vtable that needs to be initialized
226 * This routine calls the class constructor for @vtable.
229 mono_runtime_class_init (MonoVTable *vtable)
231 mono_runtime_class_init_full (vtable, TRUE);
235 * mono_runtime_class_init_full:
236 * @vtable that neeeds to be initialized
237 * @raise_exception is TRUE, exceptions are raised intead of returned
241 mono_runtime_class_init_full (MonoVTable *vtable, gboolean raise_exception)
244 MonoException *exc_to_throw;
245 MonoMethod *method = NULL;
251 if (vtable->initialized)
255 klass = vtable->klass;
257 if (!klass->image->checked_module_cctor) {
258 mono_image_check_for_module_cctor (klass->image);
259 if (klass->image->has_module_cctor) {
260 MonoClass *module_klass = mono_class_get (klass->image, MONO_TOKEN_TYPE_DEF | 1);
261 mono_runtime_class_init (mono_class_vtable (vtable->domain, module_klass));
264 method = mono_class_get_cctor (klass);
267 MonoDomain *domain = vtable->domain;
268 TypeInitializationLock *lock;
269 guint32 tid = GetCurrentThreadId();
270 int do_initialization = 0;
271 MonoDomain *last_domain = NULL;
273 mono_type_initialization_lock ();
274 /* double check... */
275 if (vtable->initialized) {
276 mono_type_initialization_unlock ();
279 if (vtable->init_failed) {
280 mono_type_initialization_unlock ();
282 /* The type initialization already failed once, rethrow the same exception */
284 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
285 return get_type_init_exception_for_vtable (vtable);
287 lock = g_hash_table_lookup (type_initialization_hash, vtable);
289 /* This thread will get to do the initialization */
290 if (mono_domain_get () != domain) {
291 /* Transfer into the target domain */
292 last_domain = mono_domain_get ();
293 if (!mono_domain_set (domain, FALSE)) {
294 vtable->initialized = 1;
295 mono_type_initialization_unlock ();
297 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
298 return mono_get_exception_appdomain_unloaded ();
301 lock = g_malloc (sizeof(TypeInitializationLock));
302 InitializeCriticalSection (&lock->initialization_section);
303 lock->initializing_tid = tid;
304 lock->waiting_count = 1;
306 /* grab the vtable lock while this thread still owns type_initialization_section */
307 EnterCriticalSection (&lock->initialization_section);
308 g_hash_table_insert (type_initialization_hash, vtable, lock);
309 do_initialization = 1;
312 TypeInitializationLock *pending_lock;
314 if (lock->initializing_tid == tid || lock->done) {
315 mono_type_initialization_unlock ();
318 /* see if the thread doing the initialization is already blocked on this thread */
319 blocked = GUINT_TO_POINTER (lock->initializing_tid);
320 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
321 if (pending_lock->initializing_tid == tid) {
322 if (!pending_lock->done) {
323 mono_type_initialization_unlock ();
326 /* the thread doing the initialization is blocked on this thread,
327 but on a lock that has already been freed. It just hasn't got
332 blocked = GUINT_TO_POINTER (pending_lock->initializing_tid);
334 ++lock->waiting_count;
335 /* record the fact that we are waiting on the initializing thread */
336 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
338 mono_type_initialization_unlock ();
340 if (do_initialization) {
341 mono_runtime_invoke (method, NULL, NULL, (MonoObject **) &exc);
343 /* If the initialization failed, mark the class as unusable. */
344 /* Avoid infinite loops */
346 (klass->image == mono_defaults.corlib &&
347 !strcmp (klass->name_space, "System") &&
348 !strcmp (klass->name, "TypeInitializationException")))) {
349 vtable->init_failed = 1;
351 if (klass->name_space && *klass->name_space)
352 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
354 full_name = g_strdup (klass->name);
355 exc_to_throw = mono_get_exception_type_initialization (full_name, exc);
359 * Store the exception object so it could be thrown on subsequent
362 mono_domain_lock (domain);
363 if (!domain->type_init_exception_hash)
364 domain->type_init_exception_hash = mono_g_hash_table_new_type (mono_aligned_addr_hash, NULL, MONO_HASH_VALUE_GC);
365 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
366 mono_domain_unlock (domain);
370 mono_domain_set (last_domain, TRUE);
372 LeaveCriticalSection (&lock->initialization_section);
374 /* this just blocks until the initializing thread is done */
375 EnterCriticalSection (&lock->initialization_section);
376 LeaveCriticalSection (&lock->initialization_section);
379 mono_type_initialization_lock ();
380 if (lock->initializing_tid != tid)
381 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
382 --lock->waiting_count;
383 if (lock->waiting_count == 0) {
384 DeleteCriticalSection (&lock->initialization_section);
385 g_hash_table_remove (type_initialization_hash, vtable);
388 if (!vtable->init_failed)
389 vtable->initialized = 1;
390 mono_type_initialization_unlock ();
392 if (vtable->init_failed) {
393 /* Either we were the initializing thread or we waited for the initialization */
395 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
396 return get_type_init_exception_for_vtable (vtable);
399 vtable->initialized = 1;
406 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
408 MonoVTable *vtable = (MonoVTable*)key;
410 TypeInitializationLock *lock = (TypeInitializationLock*) value;
411 if (lock->initializing_tid == GPOINTER_TO_UINT (user) && !lock->done) {
414 * Have to set this since it cannot be set by the normal code in
415 * mono_runtime_class_init (). In this case, the exception object is not stored,
416 * and get_type_init_exception_for_class () needs to be aware of this.
418 vtable->init_failed = 1;
419 LeaveCriticalSection (&lock->initialization_section);
420 --lock->waiting_count;
421 if (lock->waiting_count == 0) {
422 DeleteCriticalSection (&lock->initialization_section);
431 mono_release_type_locks (MonoThread *thread)
433 mono_type_initialization_lock ();
434 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, (gpointer)(gsize)(thread->tid));
435 mono_type_initialization_unlock ();
439 default_trampoline (MonoMethod *method)
445 default_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
447 g_assert_not_reached ();
453 default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target)
455 g_error ("remoting not installed");
460 default_delegate_trampoline (MonoClass *klass)
462 g_assert_not_reached ();
466 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
467 static MonoJumpTrampoline arch_create_jump_trampoline = default_jump_trampoline;
468 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
469 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
470 static MonoVTableTrampoline arch_create_vtable_trampoline;
471 static MonoImtThunkBuilder imt_thunk_builder = NULL;
472 #define ARCH_USE_IMT (imt_thunk_builder != NULL)
473 #if (MONO_IMT_SIZE > 32)
474 #error "MONO_IMT_SIZE cannot be larger than 32"
478 mono_install_trampoline (MonoTrampoline func)
480 arch_create_jit_trampoline = func? func: default_trampoline;
484 mono_install_jump_trampoline (MonoJumpTrampoline func)
486 arch_create_jump_trampoline = func? func: default_jump_trampoline;
490 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
492 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
496 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
498 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
502 mono_install_vtable_trampoline (MonoVTableTrampoline func)
504 arch_create_vtable_trampoline = func;
508 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
509 imt_thunk_builder = func;
512 static MonoCompileFunc default_mono_compile_method = NULL;
515 * mono_install_compile_method:
516 * @func: function to install
518 * This is a VM internal routine
521 mono_install_compile_method (MonoCompileFunc func)
523 default_mono_compile_method = func;
527 * mono_compile_method:
528 * @method: The method to compile.
530 * This JIT-compiles the method, and returns the pointer to the native code
534 mono_compile_method (MonoMethod *method)
536 if (!default_mono_compile_method) {
537 g_error ("compile method called on uninitialized runtime");
540 return default_mono_compile_method (method);
544 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
546 return arch_create_jump_trampoline (domain, method, add_sync_wrapper);
550 mono_runtime_create_delegate_trampoline (MonoClass *klass)
552 return arch_create_delegate_trampoline (klass);
555 static MonoFreeMethodFunc default_mono_free_method = NULL;
558 * mono_install_free_method:
559 * @func: pointer to the MonoFreeMethodFunc used to release a method
561 * This is an internal VM routine, it is used for the engines to
562 * register a handler to release the resources associated with a method.
564 * Methods are freed when no more references to the delegate that holds
568 mono_install_free_method (MonoFreeMethodFunc func)
570 default_mono_free_method = func;
574 * mono_runtime_free_method:
575 * @domain; domain where the method is hosted
576 * @method: method to release
578 * This routine is invoked to free the resources associated with
579 * a method that has been JIT compiled. This is used to discard
580 * methods that were used only temporarily (for example, used in marshalling)
584 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
586 if (default_mono_free_method != NULL)
587 default_mono_free_method (domain, method);
589 mono_method_clear_object (domain, method);
591 mono_free_method (method);
595 * The vtables in the root appdomain are assumed to be reachable by other
596 * roots, and we don't use typed allocation in the other domains.
599 /* The sync block is no longer a GC pointer */
600 #define GC_HEADER_BITMAP (0)
602 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
605 compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
607 MonoClassField *field;
613 max_size = mono_class_data_size (class) / sizeof (gpointer);
615 max_size = class->instance_size / sizeof (gpointer);
616 if (max_size >= size) {
617 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
620 for (p = class; p != NULL; p = p->parent) {
621 gpointer iter = NULL;
622 while ((field = mono_class_get_fields (p, &iter))) {
626 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
628 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
631 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
634 /* FIXME: should not happen, flag as type load error */
635 if (field->type->byref)
638 if (static_fields && field->offset == -1)
642 pos = field->offset / sizeof (gpointer);
645 type = mono_type_get_underlying_type (field->type);
646 switch (type->type) {
649 case MONO_TYPE_FNPTR:
651 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
656 if (class->image != mono_defaults.corlib)
659 case MONO_TYPE_STRING:
660 case MONO_TYPE_SZARRAY:
661 case MONO_TYPE_CLASS:
662 case MONO_TYPE_OBJECT:
663 case MONO_TYPE_ARRAY:
664 g_assert ((field->offset % sizeof(gpointer)) == 0);
666 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
667 *max_set = MAX (*max_set, pos);
669 case MONO_TYPE_GENERICINST:
670 if (!mono_type_generic_inst_is_valuetype (type)) {
671 g_assert ((field->offset % sizeof(gpointer)) == 0);
673 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
674 *max_set = MAX (*max_set, pos);
679 case MONO_TYPE_VALUETYPE: {
680 MonoClass *fclass = mono_class_from_mono_type (field->type);
681 if (fclass->has_references) {
682 /* remove the object header */
683 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
697 case MONO_TYPE_BOOLEAN:
701 g_assert_not_reached ();
713 * similar to the above, but sets the bits in the bitmap for any non-ref field
714 * and ignores static fields
717 compute_class_non_ref_bitmap (MonoClass *class, gsize *bitmap, int size, int offset)
719 MonoClassField *field;
724 max_size = class->instance_size / sizeof (gpointer);
725 if (max_size >= size) {
726 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
729 for (p = class; p != NULL; p = p->parent) {
730 gpointer iter = NULL;
731 while ((field = mono_class_get_fields (p, &iter))) {
734 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
736 /* FIXME: should not happen, flag as type load error */
737 if (field->type->byref)
740 pos = field->offset / sizeof (gpointer);
743 type = mono_type_get_underlying_type (field->type);
744 switch (type->type) {
745 #if SIZEOF_VOID_P == 8
749 case MONO_TYPE_FNPTR:
754 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
755 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
756 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
759 #if SIZEOF_VOID_P == 4
763 case MONO_TYPE_FNPTR:
768 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
769 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
770 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
776 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
777 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
778 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
781 case MONO_TYPE_BOOLEAN:
784 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
786 case MONO_TYPE_STRING:
787 case MONO_TYPE_SZARRAY:
788 case MONO_TYPE_CLASS:
789 case MONO_TYPE_OBJECT:
790 case MONO_TYPE_ARRAY:
792 case MONO_TYPE_GENERICINST:
793 if (!mono_type_generic_inst_is_valuetype (type)) {
798 case MONO_TYPE_VALUETYPE: {
799 MonoClass *fclass = mono_class_from_mono_type (field->type);
800 /* remove the object header */
801 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
805 g_assert_not_reached ();
814 * mono_class_insecure_overlapping:
815 * check if a class with explicit layout has references and non-references
816 * fields overlapping.
818 * Returns: TRUE if it is insecure to load the type.
821 mono_class_insecure_overlapping (MonoClass *klass)
825 gsize default_bitmap [4] = {0};
827 gsize default_nrbitmap [4] = {0};
828 int i, insecure = FALSE;
831 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
832 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
834 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
835 int idx = i % (sizeof (bitmap [0]) * 8);
836 if (bitmap [idx] & nrbitmap [idx]) {
841 if (bitmap != default_bitmap)
843 if (nrbitmap != default_nrbitmap)
846 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
854 mono_string_alloc (int length)
856 return mono_string_new_size (mono_domain_get (), length);
860 mono_class_compute_gc_descriptor (MonoClass *class)
864 gsize default_bitmap [4] = {0};
865 static gboolean gcj_inited = FALSE;
870 mono_register_jit_icall (mono_object_new_ptrfree, "mono_object_new_ptrfree", mono_create_icall_signature ("object ptr"), FALSE);
871 mono_register_jit_icall (mono_object_new_ptrfree_box, "mono_object_new_ptrfree_box", mono_create_icall_signature ("object ptr"), FALSE);
872 mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
873 mono_register_jit_icall (mono_string_alloc, "mono_string_alloc", mono_create_icall_signature ("object int"), FALSE);
875 #ifdef HAVE_GC_GCJ_MALLOC
877 * This is not needed unless the relevant code in mono_get_allocation_ftn () is
881 #ifdef GC_REDIRECT_TO_LOCAL
882 mono_register_jit_icall (GC_local_gcj_malloc, "GC_local_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
883 mono_register_jit_icall (GC_local_gcj_fast_malloc, "GC_local_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
885 mono_register_jit_icall (GC_gcj_malloc, "GC_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
886 mono_register_jit_icall (GC_gcj_fast_malloc, "GC_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
891 mono_loader_unlock ();
895 mono_class_init (class);
897 if (class->gc_descr_inited)
900 class->gc_descr_inited = TRUE;
901 class->gc_descr = GC_NO_DESCRIPTOR;
903 bitmap = default_bitmap;
904 if (class == mono_defaults.string_class) {
905 class->gc_descr = (gpointer)mono_gc_make_descr_for_string (bitmap, 2);
906 } else if (class->rank) {
907 mono_class_compute_gc_descriptor (class->element_class);
908 if (!class->element_class->valuetype) {
910 class->gc_descr = mono_gc_make_descr_for_array (TRUE, &abm, 1, sizeof (gpointer));
911 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
912 class->name_space, class->name);*/
914 /* remove the object header */
915 bitmap = compute_class_bitmap (class->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
916 class->gc_descr = mono_gc_make_descr_for_array (TRUE, bitmap, mono_array_element_size (class) / sizeof (gpointer), mono_array_element_size (class));
917 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
918 class->name_space, class->name);*/
919 if (bitmap != default_bitmap)
923 /*static int count = 0;
926 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
927 class->gc_descr = (gpointer)mono_gc_make_descr_for_object (bitmap, max_set + 1, class->instance_size);
929 if (class->gc_descr == GC_NO_DESCRIPTOR)
930 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
932 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
933 if (bitmap != default_bitmap)
939 * field_is_special_static:
940 * @fklass: The MonoClass to look up.
941 * @field: The MonoClassField describing the field.
943 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
944 * SPECIAL_STATIC_NONE otherwise.
947 field_is_special_static (MonoClass *fklass, MonoClassField *field)
949 MonoCustomAttrInfo *ainfo;
951 ainfo = mono_custom_attrs_from_field (fklass, field);
954 for (i = 0; i < ainfo->num_attrs; ++i) {
955 MonoClass *klass = ainfo->attrs [i].ctor->klass;
956 if (klass->image == mono_defaults.corlib) {
957 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
958 mono_custom_attrs_free (ainfo);
959 return SPECIAL_STATIC_THREAD;
961 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
962 mono_custom_attrs_free (ainfo);
963 return SPECIAL_STATIC_CONTEXT;
967 mono_custom_attrs_free (ainfo);
968 return SPECIAL_STATIC_NONE;
971 static gpointer imt_trampoline = NULL;
974 mono_install_imt_trampoline (gpointer tramp_code)
976 imt_trampoline = tramp_code;
979 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
980 #define mix(a,b,c) { \
981 a -= c; a ^= rot(c, 4); c += b; \
982 b -= a; b ^= rot(a, 6); a += c; \
983 c -= b; c ^= rot(b, 8); b += a; \
984 a -= c; a ^= rot(c,16); c += b; \
985 b -= a; b ^= rot(a,19); a += c; \
986 c -= b; c ^= rot(b, 4); b += a; \
988 #define final(a,b,c) { \
989 c ^= b; c -= rot(b,14); \
990 a ^= c; a -= rot(c,11); \
991 b ^= a; b -= rot(a,25); \
992 c ^= b; c -= rot(b,16); \
993 a ^= c; a -= rot(c,4); \
994 b ^= a; b -= rot(a,14); \
995 c ^= b; c -= rot(b,24); \
999 mono_method_get_imt_slot (MonoMethod *method)
1001 MonoMethodSignature *sig;
1003 guint32 *hashes_start, *hashes;
1007 /* This can be used to stress tests the collision code */
1011 * We do this to simplify generic sharing. It will hurt
1012 * performance in cases where a class implements two different
1013 * instantiations of the same generic interface.
1014 * The code in build_imt_slots () depends on this.
1016 if (method->is_inflated)
1017 method = ((MonoMethodInflated*)method)->declaring;
1019 sig = mono_method_signature (method);
1020 hashes_count = sig->param_count + 4;
1021 hashes_start = malloc (hashes_count * sizeof (guint32));
1022 hashes = hashes_start;
1024 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1025 printf ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod\n",
1026 method->klass->name_space, method->klass->name, method->name);
1027 g_assert_not_reached ();
1030 /* Initialize hashes */
1031 hashes [0] = g_str_hash (method->klass->name);
1032 hashes [1] = g_str_hash (method->klass->name_space);
1033 hashes [2] = g_str_hash (method->name);
1034 hashes [3] = mono_metadata_type_hash (sig->ret);
1035 for (i = 0; i < sig->param_count; i++) {
1036 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1039 /* Setup internal state */
1040 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1042 /* Handle most of the hashes */
1043 while (hashes_count > 3) {
1052 /* Handle the last 3 hashes (all the case statements fall through) */
1053 switch (hashes_count) {
1054 case 3 : c += hashes [2];
1055 case 2 : b += hashes [1];
1056 case 1 : a += hashes [0];
1058 case 0: /* nothing left to add */
1062 free (hashes_start);
1063 /* Report the result */
1064 return c % MONO_IMT_SIZE;
1073 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1074 guint32 imt_slot = mono_method_get_imt_slot (method);
1075 MonoImtBuilderEntry *entry;
1077 if (slot_num >= 0 && imt_slot != slot_num) {
1078 /* we build just a single imt slot and this is not it */
1082 entry = g_malloc0 (sizeof (MonoImtBuilderEntry));
1083 entry->key = method;
1084 entry->value.vtable_slot = vtable_slot;
1085 entry->next = imt_builder [imt_slot];
1086 if (imt_builder [imt_slot] != NULL) {
1087 entry->children = imt_builder [imt_slot]->children + 1;
1088 if (entry->children == 1) {
1089 mono_stats.imt_slots_with_collisions++;
1090 *imt_collisions_bitmap |= (1 << imt_slot);
1093 entry->children = 0;
1094 mono_stats.imt_used_slots++;
1096 imt_builder [imt_slot] = entry;
1098 printf ("Added IMT slot for method (%p) %s.%s.%s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1099 method, method->klass->name_space, method->klass->name,
1100 method->name, imt_slot, vtable_slot, entry->children);
1106 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1108 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1112 e->method->klass->name_space,
1113 e->method->klass->name,
1116 printf (" * %s: NULL\n", message);
1122 compare_imt_builder_entries (const void *p1, const void *p2) {
1123 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1124 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1126 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1130 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1132 int count = end - start;
1133 int chunk_start = out_array->len;
1136 for (i = start; i < end; ++i) {
1137 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1138 item->key = sorted_array [i]->key;
1139 item->value = sorted_array [i]->value;
1140 item->has_target_code = sorted_array [i]->has_target_code;
1141 item->is_equals = TRUE;
1143 item->check_target_idx = out_array->len + 1;
1145 item->check_target_idx = 0;
1146 g_ptr_array_add (out_array, item);
1149 int middle = start + count / 2;
1150 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1152 item->key = sorted_array [middle]->key;
1153 item->is_equals = FALSE;
1154 g_ptr_array_add (out_array, item);
1155 imt_emit_ir (sorted_array, start, middle, out_array);
1156 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1162 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1163 int number_of_entries = entries->children + 1;
1164 MonoImtBuilderEntry **sorted_array = malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1165 GPtrArray *result = g_ptr_array_new ();
1166 MonoImtBuilderEntry *current_entry;
1169 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1170 sorted_array [i] = current_entry;
1172 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1174 /*for (i = 0; i < number_of_entries; i++) {
1175 print_imt_entry (" sorted array:", sorted_array [i], i);
1178 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1180 free (sorted_array);
1185 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1187 if (imt_builder_entry != NULL) {
1188 if (imt_builder_entry->children == 0 && !fail_tramp) {
1189 /* No collision, return the vtable slot contents */
1190 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1192 /* Collision, build the thunk */
1193 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1196 result = imt_thunk_builder (vtable, domain,
1197 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1198 for (i = 0; i < imt_ir->len; ++i)
1199 g_free (g_ptr_array_index (imt_ir, i));
1200 g_ptr_array_free (imt_ir, TRUE);
1212 static MonoImtBuilderEntry*
1213 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1216 * LOCKING: requires the loader and domain locks.
1220 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1224 guint32 imt_collisions_bitmap = 0;
1225 MonoImtBuilderEntry **imt_builder = calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1226 int method_count = 0;
1227 gboolean record_method_count_for_max_collisions = FALSE;
1228 gboolean has_generic_virtual = FALSE;
1231 printf ("Building IMT for class %s.%s\n", klass->name_space, klass->name);
1233 for (i = 0; i < klass->interface_offsets_count; ++i) {
1234 MonoClass *iface = klass->interfaces_packed [i];
1235 int interface_offset = klass->interface_offsets_packed [i];
1236 int method_slot_in_interface;
1237 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1240 if (slot_num >= 0 && iface->is_inflated) {
1242 * The imt slot of the method is the same as for its declaring method,
1243 * see the comment in mono_method_get_imt_slot (), so we can
1244 * avoid inflating methods which will be discarded by
1245 * add_imt_builder_entry anyway.
1247 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1248 if (mono_method_get_imt_slot (method) != slot_num)
1251 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1252 if (method->is_generic) {
1253 has_generic_virtual = TRUE;
1256 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1259 if (extra_interfaces) {
1260 int interface_offset = klass->vtable_size;
1262 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1263 MonoClass* iface = list_item->data;
1264 int method_slot_in_interface;
1265 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1266 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1267 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1269 interface_offset += iface->method.count;
1272 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1273 /* overwrite the imt slot only if we're building all the entries or if
1274 * we're building this specific one
1276 if (slot_num < 0 || i == slot_num) {
1277 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1280 if (imt_builder [i]) {
1281 MonoImtBuilderEntry *entry;
1283 /* Link entries with imt_builder [i] */
1284 for (entry = entries; entry->next; entry = entry->next)
1286 entry->next = imt_builder [i];
1287 entries->children += imt_builder [i]->children + 1;
1289 imt_builder [i] = entries;
1292 if (has_generic_virtual) {
1294 * There might be collisions later when the the thunk is expanded.
1296 imt_collisions_bitmap |= (1 << i);
1299 * The IMT thunk might be called with an instance of one of the
1300 * generic virtual methods, so has to fallback to the IMT trampoline.
1302 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], imt_trampoline);
1304 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1308 printf ("initialize_imt_slot[%d]: %p\n", i, imt [i]);
1310 if (imt_builder [i] != NULL) {
1311 int methods_in_slot = imt_builder [i]->children + 1;
1312 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1313 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1314 record_method_count_for_max_collisions = TRUE;
1316 method_count += methods_in_slot;
1320 mono_stats.imt_number_of_methods += method_count;
1321 if (record_method_count_for_max_collisions) {
1322 mono_stats.imt_method_count_when_max_collisions = method_count;
1325 for (i = 0; i < MONO_IMT_SIZE; i++) {
1326 MonoImtBuilderEntry* entry = imt_builder [i];
1327 while (entry != NULL) {
1328 MonoImtBuilderEntry* next = entry->next;
1334 /* we OR the bitmap since we may build just a single imt slot at a time */
1335 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1339 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1340 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1344 * mono_vtable_build_imt_slot:
1345 * @vtable: virtual object table struct
1346 * @imt_slot: slot in the IMT table
1348 * Fill the given @imt_slot in the IMT table of @vtable with
1349 * a trampoline or a thunk for the case of collisions.
1350 * This is part of the internal mono API.
1352 * LOCKING: Take the domain lock.
1355 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1357 gpointer *imt = (gpointer*)vtable;
1358 imt -= MONO_IMT_SIZE;
1359 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1361 /* no support for extra interfaces: the proxy objects will need
1362 * to build the complete IMT
1363 * Update and heck needs to ahppen inside the proper domain lock, as all
1364 * the changes made to a MonoVTable.
1366 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1367 mono_domain_lock (vtable->domain);
1368 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1369 if (imt [imt_slot] == imt_trampoline)
1370 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1371 mono_domain_unlock (vtable->domain);
1372 mono_loader_unlock ();
1377 * The first two free list entries both belong to the wait list: The
1378 * first entry is the pointer to the head of the list and the second
1379 * entry points to the last element. That way appending and removing
1380 * the first element are both O(1) operations.
1382 #define NUM_FREE_LISTS 12
1383 #define FIRST_FREE_LIST_SIZE 64
1384 #define MAX_WAIT_LENGTH 50
1385 #define THUNK_THRESHOLD 10
1388 * LOCKING: The domain lock must be held.
1391 init_thunk_free_lists (MonoDomain *domain)
1393 if (domain->thunk_free_lists)
1395 domain->thunk_free_lists = mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1399 list_index_for_size (int item_size)
1402 int size = FIRST_FREE_LIST_SIZE;
1404 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1413 * mono_method_alloc_generic_virtual_thunk:
1415 * @size: size in bytes
1417 * Allocs size bytes to be used for the code of a generic virtual
1418 * thunk. It's either allocated from the domain's code manager or
1419 * reused from a previously invalidated piece.
1421 * LOCKING: The domain lock must be held.
1424 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1426 static gboolean inited = FALSE;
1427 static int generic_virtual_thunks_size = 0;
1431 MonoThunkFreeList **l;
1433 init_thunk_free_lists (domain);
1435 size += sizeof (guint32);
1436 if (size < sizeof (MonoThunkFreeList))
1437 size = sizeof (MonoThunkFreeList);
1439 i = list_index_for_size (size);
1440 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1441 if ((*l)->size >= size) {
1442 MonoThunkFreeList *item = *l;
1444 return ((guint32*)item) + 1;
1448 /* no suitable item found - search lists of larger sizes */
1449 while (++i < NUM_FREE_LISTS) {
1450 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1453 g_assert (item->size > size);
1454 domain->thunk_free_lists [i] = item->next;
1455 return ((guint32*)item) + 1;
1458 /* still nothing found - allocate it */
1460 mono_counters_register ("Generic virtual thunk bytes",
1461 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1464 generic_virtual_thunks_size += size;
1466 p = mono_domain_code_reserve (domain, size);
1473 * LOCKING: The domain lock must be held.
1476 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1479 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1481 init_thunk_free_lists (domain);
1483 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1484 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1485 int length = item->length;
1488 /* unlink the first item from the wait list */
1489 domain->thunk_free_lists [0] = item->next;
1490 domain->thunk_free_lists [0]->length = length - 1;
1492 i = list_index_for_size (item->size);
1494 /* put it in the free list */
1495 item->next = domain->thunk_free_lists [i];
1496 domain->thunk_free_lists [i] = item;
1500 if (domain->thunk_free_lists [1]) {
1501 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1502 domain->thunk_free_lists [0]->length++;
1504 g_assert (!domain->thunk_free_lists [0]);
1506 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1507 domain->thunk_free_lists [0]->length = 1;
1511 typedef struct _GenericVirtualCase {
1515 struct _GenericVirtualCase *next;
1516 } GenericVirtualCase;
1519 * get_generic_virtual_entries:
1521 * Return IMT entries for the generic virtual method instances for vtable slot
1524 static MonoImtBuilderEntry*
1525 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1527 GenericVirtualCase *list;
1528 MonoImtBuilderEntry *entries;
1530 mono_domain_lock (domain);
1531 if (!domain->generic_virtual_cases)
1532 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1534 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1537 for (; list; list = list->next) {
1538 MonoImtBuilderEntry *entry;
1540 if (list->count < THUNK_THRESHOLD)
1543 entry = g_new0 (MonoImtBuilderEntry, 1);
1544 entry->key = list->method;
1545 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1546 entry->has_target_code = 1;
1548 entry->children = entries->children + 1;
1549 entry->next = entries;
1553 mono_domain_unlock (domain);
1555 /* FIXME: Leaking memory ? */
1560 * mono_method_add_generic_virtual_invocation:
1562 * @vtable_slot: pointer to the vtable slot
1563 * @method: the inflated generic virtual method
1564 * @code: the method's code
1566 * Registers a call via unmanaged code to a generic virtual method
1567 * instantiation. If the number of calls reaches a threshold
1568 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1569 * virtual method thunk.
1572 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1573 gpointer *vtable_slot,
1574 MonoMethod *method, gpointer code)
1576 static gboolean inited = FALSE;
1577 static int num_added = 0;
1579 GenericVirtualCase *gvc, *list;
1580 MonoImtBuilderEntry *entries;
1583 gpointer vtable_trampoline = NULL;
1585 mono_domain_lock (domain);
1586 if (!domain->generic_virtual_cases)
1587 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1589 /* Check whether the case was already added */
1590 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1593 if (gvc->method == method)
1598 /* If not found, make a new one */
1600 gvc = mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1601 gvc->method = method;
1604 gvc->next = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1606 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1609 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1615 if (++gvc->count == THUNK_THRESHOLD) {
1616 gpointer *old_thunk = *vtable_slot;
1618 if (arch_create_vtable_trampoline)
1619 vtable_trampoline = arch_create_vtable_trampoline (vtable);
1621 if ((gpointer)vtable_slot < (gpointer)vtable)
1622 /* Force the rebuild of the thunk at the next call */
1623 *vtable_slot = imt_trampoline;
1625 entries = get_generic_virtual_entries (domain, vtable_slot);
1627 sorted = imt_sort_slot_entries (entries);
1629 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1633 MonoImtBuilderEntry *next = entries->next;
1638 for (i = 0; i < sorted->len; ++i)
1639 g_free (g_ptr_array_index (sorted, i));
1640 g_ptr_array_free (sorted, TRUE);
1643 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1644 invalidate_generic_virtual_thunk (domain, old_thunk);
1647 mono_domain_unlock (domain);
1650 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class);
1653 * mono_class_vtable:
1654 * @domain: the application domain
1655 * @class: the class to initialize
1657 * VTables are domain specific because we create domain specific code, and
1658 * they contain the domain specific static class data.
1659 * On failure, NULL is returned, and class->exception_type is set.
1662 mono_class_vtable (MonoDomain *domain, MonoClass *class)
1664 MonoClassRuntimeInfo *runtime_info;
1668 /* this check can be inlined in jitted code, too */
1669 runtime_info = class->runtime_info;
1670 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1671 return runtime_info->domain_vtables [domain->domain_id];
1672 if (class->exception_type)
1674 return mono_class_create_runtime_vtable (domain, class);
1678 * mono_class_try_get_vtable:
1679 * @domain: the application domain
1680 * @class: the class to initialize
1682 * This function tries to get the associated vtable from @class if
1683 * it was already created.
1686 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *class)
1688 MonoClassRuntimeInfo *runtime_info;
1692 runtime_info = class->runtime_info;
1693 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1694 return runtime_info->domain_vtables [domain->domain_id];
1699 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class)
1702 MonoClassRuntimeInfo *runtime_info, *old_info;
1703 MonoClassField *field;
1706 int imt_table_bytes = 0;
1707 guint32 vtable_size, class_size;
1710 gpointer *interface_offsets;
1712 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1713 mono_domain_lock (domain);
1714 runtime_info = class->runtime_info;
1715 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1716 mono_domain_unlock (domain);
1717 mono_loader_unlock ();
1718 return runtime_info->domain_vtables [domain->domain_id];
1720 if (!class->inited || class->exception_type) {
1721 if (!mono_class_init (class) || class->exception_type){
1723 mono_domain_unlock (domain);
1724 mono_loader_unlock ();
1725 exc = mono_class_get_exception_for_failure (class);
1727 mono_raise_exception (exc);
1731 mono_class_init (class);
1734 * For some classes, mono_class_init () already computed class->vtable_size, and
1735 * that is all that is needed because of the vtable trampolines.
1737 if (!class->vtable_size)
1738 mono_class_setup_vtable (class);
1740 if (class->exception_type) {
1741 mono_domain_unlock (domain);
1742 mono_loader_unlock ();
1747 vtable_size = sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
1748 if (class->interface_offsets_count) {
1749 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1750 vtable_size += sizeof (gpointer) * (MONO_IMT_SIZE);
1751 mono_stats.imt_number_of_tables++;
1752 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
1755 vtable_size = sizeof (gpointer) * (class->max_interface_id + 1) +
1756 sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
1759 mono_stats.used_class_count++;
1760 mono_stats.class_vtable_size += vtable_size;
1761 interface_offsets = mono_domain_alloc0 (domain, vtable_size);
1764 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1766 vt = (MonoVTable*) (interface_offsets + class->max_interface_id + 1);
1768 vt->rank = class->rank;
1769 vt->domain = domain;
1771 mono_class_compute_gc_descriptor (class);
1773 * We can't use typed allocation in the non-root domains, since the
1774 * collector needs the GC descriptor stored in the vtable even after
1775 * the mempool containing the vtable is destroyed when the domain is
1776 * unloaded. An alternative might be to allocate vtables in the GC
1777 * heap, but this does not seem to work (it leads to crashes inside
1778 * libgc). If that approach is tried, two gc descriptors need to be
1779 * allocated for each class: one for the root domain, and one for all
1780 * other domains. The second descriptor should contain a bit for the
1781 * vtable field in MonoObject, since we can no longer assume the
1782 * vtable is reachable by other roots after the appdomain is unloaded.
1784 #ifdef HAVE_BOEHM_GC
1785 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1786 vt->gc_descr = GC_NO_DESCRIPTOR;
1789 vt->gc_descr = class->gc_descr;
1791 if ((class_size = mono_class_data_size (class))) {
1792 if (class->has_static_refs) {
1793 gpointer statics_gc_descr;
1795 gsize default_bitmap [4] = {0};
1798 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1799 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
1800 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1801 vt->data = mono_gc_alloc_fixed (class_size, statics_gc_descr);
1802 mono_domain_add_class_static_data (domain, class, vt->data, NULL);
1803 if (bitmap != default_bitmap)
1806 vt->data = mono_domain_alloc0 (domain, class_size);
1808 mono_stats.class_static_data_size += class_size;
1813 while ((field = mono_class_get_fields (class, &iter))) {
1814 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1816 if (mono_field_is_deleted (field))
1818 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1819 gint32 special_static = class->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (class, field);
1820 if (special_static != SPECIAL_STATIC_NONE) {
1821 guint32 size, offset;
1823 size = mono_type_size (field->type, &align);
1824 offset = mono_alloc_special_static_data (special_static, size, align);
1825 if (!domain->special_static_fields)
1826 domain->special_static_fields = g_hash_table_new (NULL, NULL);
1827 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
1829 * This marks the field as special static to speed up the
1830 * checks in mono_field_static_get/set_value ().
1836 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
1837 MonoClass *fklass = mono_class_from_mono_type (field->type);
1838 const char *data = mono_field_get_data (field);
1840 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
1841 t = (char*)vt->data + field->offset;
1842 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
1845 if (fklass->valuetype) {
1846 memcpy (t, data, mono_class_value_size (fklass, NULL));
1848 /* it's a pointer type: add check */
1849 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
1856 vt->max_interface_id = class->max_interface_id;
1857 vt->interface_bitmap = class->interface_bitmap;
1859 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
1860 // class->name, class->interface_offsets_count);
1862 if (! ARCH_USE_IMT) {
1863 /* initialize interface offsets */
1864 for (i = 0; i < class->interface_offsets_count; ++i) {
1865 int interface_id = class->interfaces_packed [i]->interface_id;
1866 int slot = class->interface_offsets_packed [i];
1867 interface_offsets [class->max_interface_id - interface_id] = &(vt->vtable [slot]);
1871 /* FIXME: class_vtable_hash is basically obsolete now: remove as soon
1872 * as we change the code in appdomain.c to invalidate vtables by
1873 * looking at the possible MonoClasses created for the domain.
1875 g_hash_table_insert (domain->class_vtable_hash, class, vt);
1876 /* class->runtime_info is protected by the loader lock, both when
1877 * it it enlarged and when it is stored info.
1880 old_info = class->runtime_info;
1881 if (old_info && old_info->max_domain >= domain->domain_id) {
1882 /* someone already created a large enough runtime info */
1883 mono_memory_barrier ();
1884 old_info->domain_vtables [domain->domain_id] = vt;
1886 int new_size = domain->domain_id;
1888 new_size = MAX (new_size, old_info->max_domain);
1890 /* make the new size a power of two */
1892 while (new_size > i)
1895 /* this is a bounded memory retention issue: may want to
1896 * handle it differently when we'll have a rcu-like system.
1898 runtime_info = mono_image_alloc0 (class->image, sizeof (MonoClassRuntimeInfo) + new_size * sizeof (gpointer));
1899 runtime_info->max_domain = new_size - 1;
1900 /* copy the stuff from the older info */
1902 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
1904 runtime_info->domain_vtables [domain->domain_id] = vt;
1906 mono_memory_barrier ();
1907 class->runtime_info = runtime_info;
1910 /* Initialize vtable */
1911 if (arch_create_vtable_trampoline) {
1912 gpointer vtable_trampoline = arch_create_vtable_trampoline (vt);
1913 // This also covers the AOT case
1914 for (i = 0; i < class->vtable_size; ++i) {
1915 vt->vtable [i] = vtable_trampoline;
1918 mono_class_setup_vtable (class);
1920 for (i = 0; i < class->vtable_size; ++i) {
1923 if ((cm = class->vtable [i]))
1924 vt->vtable [i] = arch_create_jit_trampoline (cm);
1928 if (ARCH_USE_IMT && imt_table_bytes) {
1929 /* Now that the vtable is full, we can actually fill up the IMT */
1930 if (imt_trampoline) {
1931 /* lazy construction of the IMT entries enabled */
1932 for (i = 0; i < MONO_IMT_SIZE; ++i)
1933 interface_offsets [i] = imt_trampoline;
1935 build_imt (class, vt, domain, interface_offsets, NULL);
1939 mono_domain_unlock (domain);
1940 mono_loader_unlock ();
1942 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
1943 if (mono_is_security_manager_active () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND)) {
1944 MonoException *exc = mono_class_get_exception_for_failure (class);
1946 mono_raise_exception (exc);
1949 /* make sure the parent is initialized */
1951 mono_class_vtable (domain, class->parent);
1953 vt->type = mono_type_get_object (domain, &class->byval_arg);
1954 if (class->contextbound)
1963 * mono_class_proxy_vtable:
1964 * @domain: the application domain
1965 * @remove_class: the remote class
1967 * Creates a vtable for transparent proxies. It is basically
1968 * a copy of the real vtable of the class wrapped in @remote_class,
1969 * but all function pointers invoke the remoting functions, and
1970 * vtable->klass points to the transparent proxy class, and not to @class.
1973 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
1975 MonoVTable *vt, *pvt;
1976 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
1978 GSList *extra_interfaces = NULL;
1979 MonoClass *class = remote_class->proxy_class;
1980 gpointer *interface_offsets;
1982 vt = mono_class_vtable (domain, class);
1983 max_interface_id = vt->max_interface_id;
1985 /* Calculate vtable space for extra interfaces */
1986 for (j = 0; j < remote_class->interface_count; j++) {
1987 MonoClass* iclass = remote_class->interfaces[j];
1991 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
1992 continue; /* interface implemented by the class */
1993 if (g_slist_find (extra_interfaces, iclass))
1996 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
1998 method_count = mono_class_num_methods (iclass);
2000 ifaces = mono_class_get_implemented_interfaces (iclass);
2002 for (i = 0; i < ifaces->len; ++i) {
2003 MonoClass *ic = g_ptr_array_index (ifaces, i);
2004 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
2005 continue; /* interface implemented by the class */
2006 if (g_slist_find (extra_interfaces, ic))
2008 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2009 method_count += mono_class_num_methods (ic);
2011 g_ptr_array_free (ifaces, TRUE);
2014 extra_interface_vtsize += method_count * sizeof (gpointer);
2015 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2019 mono_stats.imt_number_of_tables++;
2020 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
2021 vtsize = sizeof (gpointer) * (MONO_IMT_SIZE) +
2022 sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
2024 vtsize = sizeof (gpointer) * (max_interface_id + 1) +
2025 sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
2028 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2030 interface_offsets = mono_domain_alloc0 (domain, vtsize + extra_interface_vtsize);
2032 pvt = (MonoVTable*) (interface_offsets + MONO_IMT_SIZE);
2034 pvt = (MonoVTable*) (interface_offsets + max_interface_id + 1);
2035 memcpy (pvt, vt, sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer));
2037 pvt->klass = mono_defaults.transparent_proxy_class;
2038 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2039 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2041 /* initialize vtable */
2042 mono_class_setup_vtable (class);
2043 for (i = 0; i < class->vtable_size; ++i) {
2046 if ((cm = class->vtable [i]))
2047 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2049 pvt->vtable [i] = NULL;
2052 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2053 /* create trampolines for abstract methods */
2054 for (k = class; k; k = k->parent) {
2056 gpointer iter = NULL;
2057 while ((m = mono_class_get_methods (k, &iter)))
2058 if (!pvt->vtable [m->slot])
2059 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2063 pvt->max_interface_id = max_interface_id;
2064 pvt->interface_bitmap = mono_domain_alloc0 (domain, sizeof (guint8) * (max_interface_id/8 + 1 ));
2066 if (! ARCH_USE_IMT) {
2067 /* initialize interface offsets */
2068 for (i = 0; i < class->interface_offsets_count; ++i) {
2069 int interface_id = class->interfaces_packed [i]->interface_id;
2070 int slot = class->interface_offsets_packed [i];
2071 interface_offsets [class->max_interface_id - interface_id] = &(pvt->vtable [slot]);
2074 for (i = 0; i < class->interface_offsets_count; ++i) {
2075 int interface_id = class->interfaces_packed [i]->interface_id;
2076 pvt->interface_bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2079 if (extra_interfaces) {
2080 int slot = class->vtable_size;
2086 /* Create trampolines for the methods of the interfaces */
2087 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2088 interf = list_item->data;
2090 if (! ARCH_USE_IMT) {
2091 interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
2093 pvt->interface_bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2097 while ((cm = mono_class_get_methods (interf, &iter)))
2098 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2100 slot += mono_class_num_methods (interf);
2102 if (! ARCH_USE_IMT) {
2103 g_slist_free (extra_interfaces);
2108 /* Now that the vtable is full, we can actually fill up the IMT */
2109 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
2110 if (extra_interfaces) {
2111 g_slist_free (extra_interfaces);
2119 * mono_class_field_is_special_static:
2121 * Returns whether @field is a thread/context static field.
2124 mono_class_field_is_special_static (MonoClassField *field)
2126 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2128 if (mono_field_is_deleted (field))
2130 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2131 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2138 * mono_class_has_special_static_fields:
2140 * Returns whenever @klass has any thread/context static fields.
2143 mono_class_has_special_static_fields (MonoClass *klass)
2145 MonoClassField *field;
2149 while ((field = mono_class_get_fields (klass, &iter))) {
2150 g_assert (field->parent == klass);
2151 if (mono_class_field_is_special_static (field))
2159 * create_remote_class_key:
2160 * Creates an array of pointers that can be used as a hash key for a remote class.
2161 * The first element of the array is the number of pointers.
2164 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2169 if (remote_class == NULL) {
2170 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2171 key = g_malloc (sizeof(gpointer) * 3);
2172 key [0] = GINT_TO_POINTER (2);
2173 key [1] = mono_defaults.marshalbyrefobject_class;
2174 key [2] = extra_class;
2176 key = g_malloc (sizeof(gpointer) * 2);
2177 key [0] = GINT_TO_POINTER (1);
2178 key [1] = extra_class;
2181 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2182 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2183 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2184 key [1] = remote_class->proxy_class;
2186 // Keep the list of interfaces sorted
2187 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2188 if (extra_class && remote_class->interfaces [i] > extra_class) {
2189 key [j++] = extra_class;
2192 key [j] = remote_class->interfaces [i];
2195 key [j] = extra_class;
2197 // Replace the old class. The interface list is the same
2198 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2199 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2200 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2201 for (i = 0; i < remote_class->interface_count; i++)
2202 key [2 + i] = remote_class->interfaces [i];
2210 * copy_remote_class_key:
2212 * Make a copy of KEY in the domain and return the copy.
2215 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2217 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2218 gpointer *mp_key = mono_domain_alloc (domain, key_size);
2220 memcpy (mp_key, key, key_size);
2226 * mono_remote_class:
2227 * @domain: the application domain
2228 * @class_name: name of the remote class
2230 * Creates and initializes a MonoRemoteClass object for a remote type.
2234 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2236 MonoRemoteClass *rc;
2237 gpointer* key, *mp_key;
2239 key = create_remote_class_key (NULL, proxy_class);
2241 mono_domain_lock (domain);
2242 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2246 mono_domain_unlock (domain);
2250 mp_key = copy_remote_class_key (domain, key);
2254 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2255 rc = mono_domain_alloc (domain, sizeof(MonoRemoteClass) + sizeof(MonoClass*));
2256 rc->interface_count = 1;
2257 rc->interfaces [0] = proxy_class;
2258 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2260 rc = mono_domain_alloc (domain, sizeof(MonoRemoteClass));
2261 rc->interface_count = 0;
2262 rc->proxy_class = proxy_class;
2265 rc->default_vtable = NULL;
2266 rc->xdomain_vtable = NULL;
2267 rc->proxy_class_name = mono_string_to_utf8_mp (domain->mp, class_name);
2268 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2270 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2272 mono_domain_unlock (domain);
2277 * clone_remote_class:
2278 * Creates a copy of the remote_class, adding the provided class or interface
2280 static MonoRemoteClass*
2281 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2283 MonoRemoteClass *rc;
2284 gpointer* key, *mp_key;
2286 key = create_remote_class_key (remote_class, extra_class);
2287 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2293 mp_key = copy_remote_class_key (domain, key);
2297 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2299 rc = mono_domain_alloc (domain, sizeof(MonoRemoteClass) + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2300 rc->proxy_class = remote_class->proxy_class;
2301 rc->interface_count = remote_class->interface_count + 1;
2303 // Keep the list of interfaces sorted, since the hash key of
2304 // the remote class depends on this
2305 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2306 if (remote_class->interfaces [i] > extra_class && i == j)
2307 rc->interfaces [j++] = extra_class;
2308 rc->interfaces [j] = remote_class->interfaces [i];
2311 rc->interfaces [j] = extra_class;
2313 // Replace the old class. The interface array is the same
2314 rc = mono_domain_alloc (domain, sizeof(MonoRemoteClass) + sizeof(MonoClass*) * remote_class->interface_count);
2315 rc->proxy_class = extra_class;
2316 rc->interface_count = remote_class->interface_count;
2317 if (rc->interface_count > 0)
2318 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2321 rc->default_vtable = NULL;
2322 rc->xdomain_vtable = NULL;
2323 rc->proxy_class_name = remote_class->proxy_class_name;
2325 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2331 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2333 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2334 mono_domain_lock (domain);
2335 if (rp->target_domain_id != -1) {
2336 if (remote_class->xdomain_vtable == NULL)
2337 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2338 mono_domain_unlock (domain);
2339 mono_loader_unlock ();
2340 return remote_class->xdomain_vtable;
2342 if (remote_class->default_vtable == NULL) {
2345 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2346 klass = mono_class_from_mono_type (type);
2347 if ((klass->is_com_object || (mono_defaults.com_object_class && klass == mono_defaults.com_object_class)) && !mono_class_vtable (mono_domain_get (), klass)->remote)
2348 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2350 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2353 mono_domain_unlock (domain);
2354 mono_loader_unlock ();
2355 return remote_class->default_vtable;
2359 * mono_upgrade_remote_class:
2360 * @domain: the application domain
2361 * @tproxy: the proxy whose remote class has to be upgraded.
2362 * @klass: class to which the remote class can be casted.
2364 * Updates the vtable of the remote class by adding the necessary method slots
2365 * and interface offsets so it can be safely casted to klass. klass can be a
2366 * class or an interface.
2369 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2371 MonoTransparentProxy *tproxy;
2372 MonoRemoteClass *remote_class;
2373 gboolean redo_vtable;
2375 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2376 mono_domain_lock (domain);
2378 tproxy = (MonoTransparentProxy*) proxy_object;
2379 remote_class = tproxy->remote_class;
2381 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2384 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2385 if (remote_class->interfaces [i] == klass)
2386 redo_vtable = FALSE;
2389 redo_vtable = (remote_class->proxy_class != klass);
2393 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2394 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2397 mono_domain_unlock (domain);
2398 mono_loader_unlock ();
2403 * mono_object_get_virtual_method:
2404 * @obj: object to operate on.
2407 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2408 * the instance of a callvirt of method.
2411 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2414 MonoMethod **vtable;
2416 MonoMethod *res = NULL;
2418 klass = mono_object_class (obj);
2419 if (klass == mono_defaults.transparent_proxy_class) {
2420 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2426 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2429 mono_class_setup_vtable (klass);
2430 vtable = klass->vtable;
2432 if (method->slot == -1) {
2433 /* method->slot might not be set for instances of generic methods */
2434 if (method->is_inflated) {
2435 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2436 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2439 g_assert_not_reached ();
2443 /* check method->slot is a valid index: perform isinstance? */
2444 if (method->slot != -1) {
2445 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2447 res = vtable [mono_class_interface_offset (klass, method->klass) + method->slot];
2449 res = vtable [method->slot];
2454 /* It may be an interface, abstract class method or generic method */
2455 if (!res || mono_method_signature (res)->generic_param_count)
2458 /* generic methods demand invoke_with_check */
2459 if (mono_method_signature (res)->generic_param_count)
2460 res = mono_marshal_get_remoting_invoke_with_check (res);
2462 res = mono_marshal_get_remoting_invoke (res);
2464 if (method->is_inflated) {
2465 /* Have to inflate the result */
2466 res = mono_class_inflate_generic_method (res, &((MonoMethodInflated*)method)->context);
2476 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2478 g_error ("runtime invoke called on uninitialized runtime");
2482 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2485 * mono_runtime_invoke:
2486 * @method: method to invoke
2487 * @obJ: object instance
2488 * @params: arguments to the method
2489 * @exc: exception information.
2491 * Invokes the method represented by @method on the object @obj.
2493 * obj is the 'this' pointer, it should be NULL for static
2494 * methods, a MonoObject* for object instances and a pointer to
2495 * the value type for value types.
2497 * The params array contains the arguments to the method with the
2498 * same convention: MonoObject* pointers for object instances and
2499 * pointers to the value type otherwise.
2501 * From unmanaged code you'll usually use the
2502 * mono_runtime_invoke() variant.
2504 * Note that this function doesn't handle virtual methods for
2505 * you, it will exec the exact method you pass: we still need to
2506 * expose a function to lookup the derived class implementation
2507 * of a virtual method (there are examples of this in the code,
2510 * You can pass NULL as the exc argument if you don't want to
2511 * catch exceptions, otherwise, *exc will be set to the exception
2512 * thrown, if any. if an exception is thrown, you can't use the
2513 * MonoObject* result from the function.
2515 * If the method returns a value type, it is boxed in an object
2519 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2521 if (mono_runtime_get_no_exec ())
2522 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2524 return default_mono_runtime_invoke (method, obj, params, exc);
2528 * mono_method_get_unmanaged_thunk:
2529 * @method: method to generate a thunk for.
2531 * Returns an unmanaged->managed thunk that can be used to call
2532 * a managed method directly from C.
2534 * The thunk's C signature closely matches the managed signature:
2536 * C#: public bool Equals (object obj);
2537 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2538 * MonoObject*, MonoException**);
2540 * The 1st ("this") parameter must not be used with static methods:
2542 * C#: public static bool ReferenceEquals (object a, object b);
2543 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2546 * The last argument must be a non-null pointer of a MonoException* pointer.
2547 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2548 * exception has been thrown in managed code. Otherwise it will point
2549 * to the MonoException* caught by the thunk. In this case, the result of
2550 * the thunk is undefined:
2552 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2553 * MonoException *ex = NULL;
2554 * Equals func = mono_method_get_unmanaged_thunk (method);
2555 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2557 * // handle exception
2560 * The calling convention of the thunk matches the platform's default
2561 * convention. This means that under Windows, C declarations must
2562 * contain the __stdcall attribute:
2564 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2565 * MonoObject*, MonoException**);
2569 * Value type arguments and return values are treated as they were objects:
2571 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2572 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2574 * Arguments must be properly boxed upon trunk's invocation, while return
2575 * values must be unboxed.
2578 mono_method_get_unmanaged_thunk (MonoMethod *method)
2580 method = mono_marshal_get_thunk_invoke_wrapper (method);
2581 return mono_compile_method (method);
2585 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
2589 gpointer *p = (gpointer*)dest;
2596 case MONO_TYPE_BOOLEAN:
2598 case MONO_TYPE_U1: {
2599 guint8 *p = (guint8*)dest;
2600 *p = value ? *(guint8*)value : 0;
2605 case MONO_TYPE_CHAR: {
2606 guint16 *p = (guint16*)dest;
2607 *p = value ? *(guint16*)value : 0;
2610 #if SIZEOF_VOID_P == 4
2615 case MONO_TYPE_U4: {
2616 gint32 *p = (gint32*)dest;
2617 *p = value ? *(gint32*)value : 0;
2620 #if SIZEOF_VOID_P == 8
2625 case MONO_TYPE_U8: {
2626 gint64 *p = (gint64*)dest;
2627 *p = value ? *(gint64*)value : 0;
2630 case MONO_TYPE_R4: {
2631 float *p = (float*)dest;
2632 *p = value ? *(float*)value : 0;
2635 case MONO_TYPE_R8: {
2636 double *p = (double*)dest;
2637 *p = value ? *(double*)value : 0;
2640 case MONO_TYPE_STRING:
2641 case MONO_TYPE_SZARRAY:
2642 case MONO_TYPE_CLASS:
2643 case MONO_TYPE_OBJECT:
2644 case MONO_TYPE_ARRAY:
2645 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2647 case MONO_TYPE_FNPTR:
2648 case MONO_TYPE_PTR: {
2649 gpointer *p = (gpointer*)dest;
2650 *p = deref_pointer? *(gpointer*)value: value;
2653 case MONO_TYPE_VALUETYPE:
2654 /* note that 't' and 'type->type' can be different */
2655 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
2656 t = mono_class_enum_basetype (type->data.klass)->type;
2660 size = mono_class_value_size (mono_class_from_mono_type (type), NULL);
2662 memset (dest, 0, size);
2664 memcpy (dest, value, size);
2667 case MONO_TYPE_GENERICINST:
2668 t = type->data.generic_class->container_class->byval_arg.type;
2671 g_warning ("got type %x", type->type);
2672 g_assert_not_reached ();
2677 * mono_field_set_value:
2678 * @obj: Instance object
2679 * @field: MonoClassField describing the field to set
2680 * @value: The value to be set
2682 * Sets the value of the field described by @field in the object instance @obj
2683 * to the value passed in @value. This method should only be used for instance
2684 * fields. For static fields, use mono_field_static_set_value.
2686 * The value must be on the native format of the field type.
2689 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
2693 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2695 dest = (char*)obj + field->offset;
2696 set_value (field->type, dest, value, FALSE);
2700 * mono_field_static_set_value:
2701 * @field: MonoClassField describing the field to set
2702 * @value: The value to be set
2704 * Sets the value of the static field described by @field
2705 * to the value passed in @value.
2707 * The value must be on the native format of the field type.
2710 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
2714 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2715 /* you cant set a constant! */
2716 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
2718 if (field->offset == -1) {
2719 /* Special static */
2720 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
2721 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
2723 dest = (char*)vt->data + field->offset;
2725 set_value (field->type, dest, value, FALSE);
2728 /* Used by the debugger */
2730 mono_vtable_get_static_field_data (MonoVTable *vt)
2736 * mono_field_get_value:
2737 * @obj: Object instance
2738 * @field: MonoClassField describing the field to fetch information from
2739 * @value: pointer to the location where the value will be stored
2741 * Use this routine to get the value of the field @field in the object
2744 * The pointer provided by value must be of the field type, for reference
2745 * types this is a MonoObject*, for value types its the actual pointer to
2750 * mono_field_get_value (obj, int_field, &i);
2753 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
2757 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2759 src = (char*)obj + field->offset;
2760 set_value (field->type, value, src, TRUE);
2764 * mono_field_get_value_object:
2765 * @domain: domain where the object will be created (if boxing)
2766 * @field: MonoClassField describing the field to fetch information from
2767 * @obj: The object instance for the field.
2769 * Returns: a new MonoObject with the value from the given field. If the
2770 * field represents a value type, the value is boxed.
2774 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
2778 MonoVTable *vtable = NULL;
2780 gboolean is_static = FALSE;
2781 gboolean is_ref = FALSE;
2783 switch (field->type->type) {
2784 case MONO_TYPE_STRING:
2785 case MONO_TYPE_OBJECT:
2786 case MONO_TYPE_CLASS:
2787 case MONO_TYPE_ARRAY:
2788 case MONO_TYPE_SZARRAY:
2793 case MONO_TYPE_BOOLEAN:
2796 case MONO_TYPE_CHAR:
2805 case MONO_TYPE_VALUETYPE:
2806 is_ref = field->type->byref;
2808 case MONO_TYPE_GENERICINST:
2809 is_ref = !field->type->data.generic_class->container_class->valuetype;
2812 g_error ("type 0x%x not handled in "
2813 "mono_field_get_value_object", field->type->type);
2817 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
2819 vtable = mono_class_vtable (domain, field->parent);
2820 if (!vtable->initialized)
2821 mono_runtime_class_init (vtable);
2826 mono_field_static_get_value (vtable, field, &o);
2828 mono_field_get_value (obj, field, &o);
2833 /* boxed value type */
2834 klass = mono_class_from_mono_type (field->type);
2835 o = mono_object_new (domain, klass);
2836 v = ((gchar *) o) + sizeof (MonoObject);
2838 mono_field_static_get_value (vtable, field, v);
2840 mono_field_get_value (obj, field, v);
2847 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
2850 const char *p = blob;
2851 mono_metadata_decode_blob_size (p, &p);
2854 case MONO_TYPE_BOOLEAN:
2857 *(guint8 *) value = *p;
2859 case MONO_TYPE_CHAR:
2862 *(guint16*) value = read16 (p);
2866 *(guint32*) value = read32 (p);
2870 *(guint64*) value = read64 (p);
2873 readr4 (p, (float*) value);
2876 readr8 (p, (double*) value);
2878 case MONO_TYPE_STRING:
2879 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
2881 case MONO_TYPE_CLASS:
2882 *(gpointer*) value = NULL;
2886 g_warning ("type 0x%02x should not be in constant table", type);
2892 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
2894 MonoTypeEnum def_type;
2897 data = mono_class_get_field_default_value (field, &def_type);
2898 mono_get_constant_value_from_blob (domain, def_type, data, value);
2902 * mono_field_static_get_value:
2903 * @vt: vtable to the object
2904 * @field: MonoClassField describing the field to fetch information from
2905 * @value: where the value is returned
2907 * Use this routine to get the value of the static field @field value.
2909 * The pointer provided by value must be of the field type, for reference
2910 * types this is a MonoObject*, for value types its the actual pointer to
2915 * mono_field_static_get_value (vt, int_field, &i);
2918 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
2922 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2924 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
2925 get_default_field_value (vt->domain, field, value);
2929 if (field->offset == -1) {
2930 /* Special static */
2931 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
2932 src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
2934 src = (char*)vt->data + field->offset;
2936 set_value (field->type, value, src, TRUE);
2940 * mono_property_set_value:
2941 * @prop: MonoProperty to set
2942 * @obj: instance object on which to act
2943 * @params: parameters to pass to the propery
2944 * @exc: optional exception
2946 * Invokes the property's set method with the given arguments on the
2947 * object instance obj (or NULL for static properties).
2949 * You can pass NULL as the exc argument if you don't want to
2950 * catch exceptions, otherwise, *exc will be set to the exception
2951 * thrown, if any. if an exception is thrown, you can't use the
2952 * MonoObject* result from the function.
2955 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
2957 default_mono_runtime_invoke (prop->set, obj, params, exc);
2961 * mono_property_get_value:
2962 * @prop: MonoProperty to fetch
2963 * @obj: instance object on which to act
2964 * @params: parameters to pass to the propery
2965 * @exc: optional exception
2967 * Invokes the property's get method with the given arguments on the
2968 * object instance obj (or NULL for static properties).
2970 * You can pass NULL as the exc argument if you don't want to
2971 * catch exceptions, otherwise, *exc will be set to the exception
2972 * thrown, if any. if an exception is thrown, you can't use the
2973 * MonoObject* result from the function.
2975 * Returns: the value from invoking the get method on the property.
2978 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
2980 return default_mono_runtime_invoke (prop->get, obj, params, exc);
2984 * mono_nullable_init:
2985 * @buf: The nullable structure to initialize.
2986 * @value: the value to initialize from
2987 * @klass: the type for the object
2989 * Initialize the nullable structure pointed to by @buf from @value which
2990 * should be a boxed value type. The size of @buf should be able to hold
2991 * as much data as the @klass->instance_size (which is the number of bytes
2992 * that will be copies).
2994 * Since Nullables have variable structure, we can not define a C
2995 * structure for them.
2998 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3000 MonoClass *param_class = klass->cast_class;
3002 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3003 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3005 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3007 memcpy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3009 memset (buf + klass->fields [0].offset - sizeof (MonoObject), 0, mono_class_value_size (param_class, NULL));
3013 * mono_nullable_box:
3014 * @buf: The buffer representing the data to be boxed
3015 * @klass: the type to box it as.
3017 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3021 mono_nullable_box (guint8 *buf, MonoClass *klass)
3023 MonoClass *param_class = klass->cast_class;
3025 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3026 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3028 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3029 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
3030 memcpy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3038 * mono_get_delegate_invoke:
3039 * @klass: The delegate class
3041 * Returns: the MonoMethod for the "Invoke" method in the delegate klass
3044 mono_get_delegate_invoke (MonoClass *klass)
3048 /* This is called at runtime, so avoid the slower search in metadata */
3049 mono_class_setup_methods (klass);
3051 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3058 * mono_runtime_delegate_invoke:
3059 * @delegate: pointer to a delegate object.
3060 * @params: parameters for the delegate.
3061 * @exc: Pointer to the exception result.
3063 * Invokes the delegate method @delegate with the parameters provided.
3065 * You can pass NULL as the exc argument if you don't want to
3066 * catch exceptions, otherwise, *exc will be set to the exception
3067 * thrown, if any. if an exception is thrown, you can't use the
3068 * MonoObject* result from the function.
3071 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3075 im = mono_get_delegate_invoke (delegate->vtable->klass);
3078 return mono_runtime_invoke (im, delegate, params, exc);
3081 static char **main_args = NULL;
3082 static int num_main_args;
3085 * mono_runtime_get_main_args:
3087 * Returns: a MonoArray with the arguments passed to the main program
3090 mono_runtime_get_main_args (void)
3094 MonoDomain *domain = mono_domain_get ();
3099 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3101 for (i = 0; i < num_main_args; ++i)
3102 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3108 fire_process_exit_event (void)
3110 MonoClassField *field;
3111 MonoDomain *domain = mono_domain_get ();
3113 MonoObject *delegate, *exc;
3115 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "ProcessExit");
3118 if (domain != mono_get_root_domain ())
3121 delegate = *(MonoObject **)(((char *)domain->domain) + field->offset);
3122 if (delegate == NULL)
3127 mono_runtime_delegate_invoke (delegate, pa, &exc);
3131 * mono_runtime_run_main:
3132 * @method: the method to start the application with (usually Main)
3133 * @argc: number of arguments from the command line
3134 * @argv: array of strings from the command line
3135 * @exc: excetption results
3137 * Execute a standard Main() method (argc/argv contains the
3138 * executable name). This method also sets the command line argument value
3139 * needed by System.Environment.
3144 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3148 MonoArray *args = NULL;
3149 MonoDomain *domain = mono_domain_get ();
3150 gchar *utf8_fullpath;
3153 g_assert (method != NULL);
3155 mono_thread_set_main (mono_thread_current ());
3157 main_args = g_new0 (char*, argc);
3158 num_main_args = argc;
3160 if (!g_path_is_absolute (argv [0])) {
3161 gchar *basename = g_path_get_basename (argv [0]);
3162 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3166 utf8_fullpath = mono_utf8_from_external (fullpath);
3167 if(utf8_fullpath == NULL) {
3168 /* Printing the arg text will cause glib to
3169 * whinge about "Invalid UTF-8", but at least
3170 * its relevant, and shows the problem text
3173 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3174 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3181 utf8_fullpath = mono_utf8_from_external (argv[0]);
3182 if(utf8_fullpath == NULL) {
3183 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3184 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3189 main_args [0] = utf8_fullpath;
3191 for (i = 1; i < argc; ++i) {
3194 utf8_arg=mono_utf8_from_external (argv[i]);
3195 if(utf8_arg==NULL) {
3196 /* Ditto the comment about Invalid UTF-8 here */
3197 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3198 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3202 main_args [i] = utf8_arg;
3206 if (mono_method_signature (method)->param_count) {
3207 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3208 for (i = 0; i < argc; ++i) {
3209 /* The encodings should all work, given that
3210 * we've checked all these args for the
3213 gchar *str = mono_utf8_from_external (argv [i]);
3214 MonoString *arg = mono_string_new (domain, str);
3215 mono_array_setref (args, i, arg);
3219 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3222 mono_assembly_set_main (method->klass->image->assembly);
3224 result = mono_runtime_exec_main (method, args, exc);
3225 fire_process_exit_event ();
3229 /* Used in call_unhandled_exception_delegate */
3231 create_unhandled_exception_eventargs (MonoObject *exc)
3235 MonoMethod *method = NULL;
3236 MonoBoolean is_terminating = TRUE;
3239 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
3242 mono_class_init (klass);
3244 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
3245 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
3249 args [1] = &is_terminating;
3251 obj = mono_object_new (mono_domain_get (), klass);
3252 mono_runtime_invoke (method, obj, args, NULL);
3257 /* Used in mono_unhandled_exception */
3259 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
3260 MonoObject *e = NULL;
3263 pa [0] = domain->domain;
3264 pa [1] = create_unhandled_exception_eventargs (exc);
3265 mono_runtime_delegate_invoke (delegate, pa, &e);
3268 gchar *msg = mono_string_to_utf8 (((MonoException *) e)->message);
3269 g_warning ("exception inside UnhandledException handler: %s\n", msg);
3274 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
3277 * mono_runtime_unhandled_exception_policy_set:
3278 * @policy: the new policy
3280 * This is a VM internal routine.
3282 * Sets the runtime policy for handling unhandled exceptions.
3285 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
3286 runtime_unhandled_exception_policy = policy;
3290 * mono_runtime_unhandled_exception_policy_get:
3292 * This is a VM internal routine.
3294 * Gets the runtime policy for handling unhandled exceptions.
3296 MonoRuntimeUnhandledExceptionPolicy
3297 mono_runtime_unhandled_exception_policy_get (void) {
3298 return runtime_unhandled_exception_policy;
3302 * mono_unhandled_exception:
3303 * @exc: exception thrown
3305 * This is a VM internal routine.
3307 * We call this function when we detect an unhandled exception
3308 * in the default domain.
3310 * It invokes the * UnhandledException event in AppDomain or prints
3311 * a warning to the console
3314 mono_unhandled_exception (MonoObject *exc)
3316 MonoDomain *current_domain = mono_domain_get ();
3317 MonoDomain *root_domain = mono_get_root_domain ();
3318 MonoClassField *field;
3319 MonoObject *current_appdomain_delegate;
3320 MonoObject *root_appdomain_delegate;
3322 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
3323 "UnhandledException");
3326 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
3327 gboolean abort_process = (mono_thread_current () == main_thread) ||
3328 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT);
3329 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
3330 if (current_domain != root_domain && (mono_framework_version () >= 2)) {
3331 current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
3333 current_appdomain_delegate = NULL;
3336 /* set exitcode only if we will abort the process */
3338 mono_environment_exitcode_set (1);
3339 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
3340 mono_print_unhandled_exception (exc);
3342 if (root_appdomain_delegate) {
3343 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
3345 if (current_appdomain_delegate) {
3346 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
3353 * Launch a new thread to execute a function
3355 * main_func is called back from the thread with main_args as the
3356 * parameter. The callback function is expected to start Main()
3357 * eventually. This function then waits for all managed threads to
3359 * It is not necesseray anymore to execute managed code in a subthread,
3360 * so this function should not be used anymore by default: just
3361 * execute the code and then call mono_thread_manage ().
3364 mono_runtime_exec_managed_code (MonoDomain *domain,
3365 MonoMainThreadFunc main_func,
3368 mono_thread_create (domain, main_func, main_args);
3370 mono_thread_manage ();
3374 * Execute a standard Main() method (args doesn't contain the
3378 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
3383 MonoCustomAttrInfo* cinfo;
3384 gboolean has_stathread_attribute;
3385 MonoThread* thread = mono_thread_current ();
3391 domain = mono_object_domain (args);
3392 if (!domain->entry_assembly) {
3394 MonoAssembly *assembly;
3396 assembly = method->klass->image->assembly;
3397 domain->entry_assembly = assembly;
3398 /* Domains created from another domain already have application_base and configuration_file set */
3399 if (domain->setup->application_base == NULL) {
3400 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
3403 if (domain->setup->configuration_file == NULL) {
3404 str = g_strconcat (assembly->image->name, ".config", NULL);
3405 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
3407 mono_set_private_bin_path_from_config (domain);
3411 cinfo = mono_custom_attrs_from_method (method);
3413 static MonoClass *stathread_attribute = NULL;
3414 if (!stathread_attribute)
3415 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
3416 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
3418 mono_custom_attrs_free (cinfo);
3420 has_stathread_attribute = FALSE;
3422 if (has_stathread_attribute) {
3423 thread->apartment_state = ThreadApartmentState_STA;
3424 } else if (mono_framework_version () == 1) {
3425 thread->apartment_state = ThreadApartmentState_Unknown;
3427 thread->apartment_state = ThreadApartmentState_MTA;
3429 mono_thread_init_apartment_state ();
3431 mono_debugger_event (MONO_DEBUGGER_EVENT_REACHED_MAIN, 0, 0);
3433 /* FIXME: check signature of method */
3434 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
3436 res = mono_runtime_invoke (method, NULL, pa, exc);
3438 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
3442 mono_environment_exitcode_set (rval);
3444 mono_runtime_invoke (method, NULL, pa, exc);
3448 /* If the return type of Main is void, only
3449 * set the exitcode if an exception was thrown
3450 * (we don't want to blow away an
3451 * explicitly-set exit code)
3454 mono_environment_exitcode_set (rval);
3458 mono_debugger_event (MONO_DEBUGGER_EVENT_MAIN_EXITED, (guint64) (gsize) rval, 0);
3464 * mono_install_runtime_invoke:
3465 * @func: Function to install
3467 * This is a VM internal routine
3470 mono_install_runtime_invoke (MonoInvokeFunc func)
3472 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
3477 * mono_runtime_invoke_array:
3478 * @method: method to invoke
3479 * @obJ: object instance
3480 * @params: arguments to the method
3481 * @exc: exception information.
3483 * Invokes the method represented by @method on the object @obj.
3485 * obj is the 'this' pointer, it should be NULL for static
3486 * methods, a MonoObject* for object instances and a pointer to
3487 * the value type for value types.
3489 * The params array contains the arguments to the method with the
3490 * same convention: MonoObject* pointers for object instances and
3491 * pointers to the value type otherwise. The _invoke_array
3492 * variant takes a C# object[] as the params argument (MonoArray
3493 * *params): in this case the value types are boxed inside the
3494 * respective reference representation.
3496 * From unmanaged code you'll usually use the
3497 * mono_runtime_invoke() variant.
3499 * Note that this function doesn't handle virtual methods for
3500 * you, it will exec the exact method you pass: we still need to
3501 * expose a function to lookup the derived class implementation
3502 * of a virtual method (there are examples of this in the code,
3505 * You can pass NULL as the exc argument if you don't want to
3506 * catch exceptions, otherwise, *exc will be set to the exception
3507 * thrown, if any. if an exception is thrown, you can't use the
3508 * MonoObject* result from the function.
3510 * If the method returns a value type, it is boxed in an object
3514 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
3517 MonoMethodSignature *sig = mono_method_signature (method);
3518 gpointer *pa = NULL;
3521 gboolean has_byref_nullables = FALSE;
3523 if (NULL != params) {
3524 pa = alloca (sizeof (gpointer) * mono_array_length (params));
3525 for (i = 0; i < mono_array_length (params); i++) {
3526 MonoType *t = sig->params [i];
3532 case MONO_TYPE_BOOLEAN:
3535 case MONO_TYPE_CHAR:
3544 case MONO_TYPE_VALUETYPE:
3545 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
3546 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
3547 pa [i] = mono_array_get (params, MonoObject*, i);
3549 has_byref_nullables = TRUE;
3551 /* MS seems to create the objects if a null is passed in */
3552 if (!mono_array_get (params, MonoObject*, i))
3553 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
3557 * We can't pass the unboxed vtype byref to the callee, since
3558 * that would mean the callee would be able to modify boxed
3559 * primitive types. So we (and MS) make a copy of the boxed
3560 * object, pass that to the callee, and replace the original
3561 * boxed object in the arg array with the copy.
3563 MonoObject *orig = mono_array_get (params, MonoObject*, i);
3564 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
3565 mono_array_setref (params, i, copy);
3568 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
3571 case MONO_TYPE_STRING:
3572 case MONO_TYPE_OBJECT:
3573 case MONO_TYPE_CLASS:
3574 case MONO_TYPE_ARRAY:
3575 case MONO_TYPE_SZARRAY:
3577 pa [i] = mono_array_addr (params, MonoObject*, i);
3578 // FIXME: I need to check this code path
3580 pa [i] = mono_array_get (params, MonoObject*, i);
3582 case MONO_TYPE_GENERICINST:
3584 t = &t->data.generic_class->container_class->this_arg;
3586 t = &t->data.generic_class->container_class->byval_arg;
3589 g_error ("type 0x%x not handled in ves_icall_InternalInvoke", sig->params [i]->type);
3594 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
3597 if (mono_class_is_nullable (method->klass)) {
3598 /* Need to create a boxed vtype instead */
3604 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
3608 obj = mono_object_new (mono_domain_get (), method->klass);
3609 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
3610 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
3612 if (method->klass->valuetype)
3613 o = mono_object_unbox (obj);
3616 } else if (method->klass->valuetype) {
3617 obj = mono_value_box (mono_domain_get (), method->klass, obj);
3620 mono_runtime_invoke (method, o, pa, exc);
3623 if (mono_class_is_nullable (method->klass)) {
3624 MonoObject *nullable;
3626 /* Convert the unboxed vtype into a Nullable structure */
3627 nullable = mono_object_new (mono_domain_get (), method->klass);
3629 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
3630 obj = mono_object_unbox (nullable);
3633 /* obj must be already unboxed if needed */
3634 res = mono_runtime_invoke (method, obj, pa, exc);
3636 if (has_byref_nullables) {
3638 * The runtime invoke wrapper already converted byref nullables back,
3639 * and stored them in pa, we just need to copy them back to the
3642 for (i = 0; i < mono_array_length (params); i++) {
3643 MonoType *t = sig->params [i];
3645 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
3646 mono_array_setref (params, i, pa [i]);
3655 arith_overflow (void)
3657 mono_raise_exception (mono_get_exception_overflow ());
3661 * mono_object_allocate:
3662 * @size: number of bytes to allocate
3664 * This is a very simplistic routine until we have our GC-aware
3667 * Returns: an allocated object of size @size, or NULL on failure.
3669 static inline void *
3670 mono_object_allocate (size_t size, MonoVTable *vtable)
3673 mono_stats.new_object_count++;
3674 ALLOC_OBJECT (o, vtable, size);
3680 * mono_object_allocate_ptrfree:
3681 * @size: number of bytes to allocate
3683 * Note that the memory allocated is not zeroed.
3684 * Returns: an allocated object of size @size, or NULL on failure.
3686 static inline void *
3687 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
3690 mono_stats.new_object_count++;
3691 ALLOC_PTRFREE (o, vtable, size);
3695 static inline void *
3696 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
3699 ALLOC_TYPED (o, size, vtable);
3700 mono_stats.new_object_count++;
3707 * @klass: the class of the object that we want to create
3709 * Returns: a newly created object whose definition is
3710 * looked up using @klass. This will not invoke any constructors,
3711 * so the consumer of this routine has to invoke any constructors on
3712 * its own to initialize the object.
3715 mono_object_new (MonoDomain *domain, MonoClass *klass)
3717 MONO_ARCH_SAVE_REGS;
3718 return mono_object_new_specific (mono_class_vtable (domain, klass));
3722 * mono_object_new_specific:
3723 * @vtable: the vtable of the object that we want to create
3725 * Returns: A newly created object with class and domain specified
3729 mono_object_new_specific (MonoVTable *vtable)
3733 MONO_ARCH_SAVE_REGS;
3735 /* check for is_com_object for COM Interop */
3736 if (vtable->remote || vtable->klass->is_com_object)
3739 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
3742 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
3745 mono_class_init (klass);
3747 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
3749 vtable->domain->create_proxy_for_type_method = im;
3752 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
3754 o = mono_runtime_invoke (im, NULL, pa, NULL);
3755 if (o != NULL) return o;
3758 return mono_object_new_alloc_specific (vtable);
3762 mono_object_new_alloc_specific (MonoVTable *vtable)
3766 if (!vtable->klass->has_references) {
3767 o = mono_object_new_ptrfree (vtable);
3768 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3769 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
3771 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
3772 o = mono_object_allocate (vtable->klass->instance_size, vtable);
3774 if (G_UNLIKELY (vtable->klass->has_finalize))
3775 mono_object_register_finalizer (o);
3777 if (G_UNLIKELY (profile_allocs))
3778 mono_profiler_allocation (o, vtable->klass);
3783 mono_object_new_fast (MonoVTable *vtable)
3786 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
3791 mono_object_new_ptrfree (MonoVTable *vtable)
3794 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
3795 #if NEED_TO_ZERO_PTRFREE
3796 /* an inline memset is much faster for the common vcase of small objects
3797 * note we assume the allocated size is a multiple of sizeof (void*).
3799 if (vtable->klass->instance_size < 128) {
3801 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
3802 p = (gpointer*)((char*)obj + sizeof (MonoObject));
3808 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
3815 mono_object_new_ptrfree_box (MonoVTable *vtable)
3818 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
3819 /* the object will be boxed right away, no need to memzero it */
3824 * mono_class_get_allocation_ftn:
3826 * @for_box: the object will be used for boxing
3827 * @pass_size_in_words:
3829 * Return the allocation function appropriate for the given class.
3833 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
3835 *pass_size_in_words = FALSE;
3837 if (!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
3838 profile_allocs = FALSE;
3840 if (vtable->klass->has_finalize || vtable->klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
3841 return mono_object_new_specific;
3843 if (!vtable->klass->has_references) {
3844 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
3846 return mono_object_new_ptrfree_box;
3847 return mono_object_new_ptrfree;
3850 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3852 return mono_object_new_fast;
3855 * FIXME: This is actually slower than mono_object_new_fast, because
3856 * of the overhead of parameter passing.
3859 *pass_size_in_words = TRUE;
3860 #ifdef GC_REDIRECT_TO_LOCAL
3861 return GC_local_gcj_fast_malloc;
3863 return GC_gcj_fast_malloc;
3868 return mono_object_new_specific;
3872 * mono_object_new_from_token:
3873 * @image: Context where the type_token is hosted
3874 * @token: a token of the type that we want to create
3876 * Returns: A newly created object whose definition is
3877 * looked up using @token in the @image image
3880 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
3884 class = mono_class_get (image, token);
3886 return mono_object_new (domain, class);
3891 * mono_object_clone:
3892 * @obj: the object to clone
3894 * Returns: A newly created object who is a shallow copy of @obj
3897 mono_object_clone (MonoObject *obj)
3902 size = obj->vtable->klass->instance_size;
3903 o = mono_object_allocate (size, obj->vtable);
3904 /* do not copy the sync state */
3905 memcpy ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
3908 if (obj->vtable->klass->has_references)
3909 mono_gc_wbarrier_object (o);
3911 if (G_UNLIKELY (profile_allocs))
3912 mono_profiler_allocation (o, obj->vtable->klass);
3914 if (obj->vtable->klass->has_finalize)
3915 mono_object_register_finalizer (o);
3920 * mono_array_full_copy:
3921 * @src: source array to copy
3922 * @dest: destination array
3924 * Copies the content of one array to another with exactly the same type and size.
3927 mono_array_full_copy (MonoArray *src, MonoArray *dest)
3929 mono_array_size_t size;
3930 MonoClass *klass = src->obj.vtable->klass;
3932 MONO_ARCH_SAVE_REGS;
3934 g_assert (klass == dest->obj.vtable->klass);
3936 size = mono_array_length (src);
3937 g_assert (size == mono_array_length (dest));
3938 size *= mono_array_element_size (klass);
3940 if (klass->element_class->valuetype) {
3941 if (klass->element_class->has_references)
3942 mono_value_copy_array (dest, 0, mono_array_addr_with_size (src, 0, 0), mono_array_length (src));
3944 memcpy (&dest->vector, &src->vector, size);
3946 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
3949 memcpy (&dest->vector, &src->vector, size);
3954 * mono_array_clone_in_domain:
3955 * @domain: the domain in which the array will be cloned into
3956 * @array: the array to clone
3958 * This routine returns a copy of the array that is hosted on the
3959 * specified MonoDomain.
3962 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
3965 mono_array_size_t size, i;
3966 mono_array_size_t *sizes;
3967 MonoClass *klass = array->obj.vtable->klass;
3969 MONO_ARCH_SAVE_REGS;
3971 if (array->bounds == NULL) {
3972 size = mono_array_length (array);
3973 o = mono_array_new_full (domain, klass, &size, NULL);
3975 size *= mono_array_element_size (klass);
3977 if (klass->element_class->valuetype) {
3978 if (klass->element_class->has_references)
3979 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
3981 memcpy (&o->vector, &array->vector, size);
3983 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
3986 memcpy (&o->vector, &array->vector, size);
3991 sizes = alloca (klass->rank * sizeof(mono_array_size_t) * 2);
3992 size = mono_array_element_size (klass);
3993 for (i = 0; i < klass->rank; ++i) {
3994 sizes [i] = array->bounds [i].length;
3995 size *= array->bounds [i].length;
3996 sizes [i + klass->rank] = array->bounds [i].lower_bound;
3998 o = mono_array_new_full (domain, klass, sizes, sizes + klass->rank);
4000 if (klass->element_class->valuetype) {
4001 if (klass->element_class->has_references)
4002 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4004 memcpy (&o->vector, &array->vector, size);
4006 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4009 memcpy (&o->vector, &array->vector, size);
4017 * @array: the array to clone
4019 * Returns: A newly created array who is a shallow copy of @array
4022 mono_array_clone (MonoArray *array)
4024 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
4027 /* helper macros to check for overflow when calculating the size of arrays */
4028 #ifdef MONO_BIG_ARRAYS
4029 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
4030 #define MYGUINT_MAX MYGUINT64_MAX
4031 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4032 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
4033 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4034 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
4035 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
4037 #define MYGUINT32_MAX 4294967295U
4038 #define MYGUINT_MAX MYGUINT32_MAX
4039 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4040 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
4041 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4042 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
4043 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
4047 * mono_array_new_full:
4048 * @domain: domain where the object is created
4049 * @array_class: array class
4050 * @lengths: lengths for each dimension in the array
4051 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
4053 * This routine creates a new array objects with the given dimensions,
4054 * lower bounds and type.
4057 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, mono_array_size_t *lengths, mono_array_size_t *lower_bounds)
4059 mono_array_size_t byte_len, len, bounds_size;
4065 if (!array_class->inited)
4066 mono_class_init (array_class);
4068 byte_len = mono_array_element_size (array_class);
4071 /* A single dimensional array with a 0 lower bound is the same as an szarray */
4072 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
4074 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
4078 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
4080 for (i = 0; i < array_class->rank; ++i) {
4081 if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
4083 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
4084 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4089 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
4090 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4092 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
4093 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4094 byte_len += sizeof (MonoArray);
4097 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
4098 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4099 byte_len = (byte_len + 3) & ~3;
4100 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
4101 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4102 byte_len += bounds_size;
4105 * Following three lines almost taken from mono_object_new ():
4106 * they need to be kept in sync.
4108 vtable = mono_class_vtable (domain, array_class);
4109 if (!array_class->has_references) {
4110 o = mono_object_allocate_ptrfree (byte_len, vtable);
4111 #if NEED_TO_ZERO_PTRFREE
4112 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4114 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4115 o = mono_object_allocate_spec (byte_len, vtable);
4117 o = mono_object_allocate (byte_len, vtable);
4120 array = (MonoArray*)o;
4121 array->max_length = len;
4124 MonoArrayBounds *bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
4125 array->bounds = bounds;
4126 for (i = 0; i < array_class->rank; ++i) {
4127 bounds [i].length = lengths [i];
4129 bounds [i].lower_bound = lower_bounds [i];
4133 if (G_UNLIKELY (profile_allocs))
4134 mono_profiler_allocation (o, array_class);
4141 * @domain: domain where the object is created
4142 * @eclass: element class
4143 * @n: number of array elements
4145 * This routine creates a new szarray with @n elements of type @eclass.
4148 mono_array_new (MonoDomain *domain, MonoClass *eclass, mono_array_size_t n)
4152 MONO_ARCH_SAVE_REGS;
4154 ac = mono_array_class_get (eclass, 1);
4157 return mono_array_new_specific (mono_class_vtable (domain, ac), n);
4161 * mono_array_new_specific:
4162 * @vtable: a vtable in the appropriate domain for an initialized class
4163 * @n: number of array elements
4165 * This routine is a fast alternative to mono_array_new() for code which
4166 * can be sure about the domain it operates in.
4169 mono_array_new_specific (MonoVTable *vtable, mono_array_size_t n)
4173 guint32 byte_len, elem_size;
4175 MONO_ARCH_SAVE_REGS;
4177 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
4182 elem_size = mono_array_element_size (vtable->klass);
4183 if (CHECK_MUL_OVERFLOW_UN (n, elem_size)) {
4184 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4187 byte_len = n * elem_size;
4188 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray))) {
4189 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4192 byte_len += sizeof (MonoArray);
4193 if (!vtable->klass->has_references) {
4194 o = mono_object_allocate_ptrfree (byte_len, vtable);
4195 #if NEED_TO_ZERO_PTRFREE
4196 ((MonoArray*)o)->bounds = NULL;
4197 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4199 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4200 o = mono_object_allocate_spec (byte_len, vtable);
4202 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4203 o = mono_object_allocate (byte_len, vtable);
4206 ao = (MonoArray *)o;
4208 if (G_UNLIKELY (profile_allocs))
4209 mono_profiler_allocation (o, vtable->klass);
4215 * mono_string_new_utf16:
4216 * @text: a pointer to an utf16 string
4217 * @len: the length of the string
4219 * Returns: A newly created string object which contains @text.
4222 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
4226 s = mono_string_new_size (domain, len);
4227 g_assert (s != NULL);
4229 memcpy (mono_string_chars (s), text, len * 2);
4235 * mono_string_new_size:
4236 * @text: a pointer to an utf16 string
4237 * @len: the length of the string
4239 * Returns: A newly created string object of @len
4242 mono_string_new_size (MonoDomain *domain, gint32 len)
4246 size_t size = (sizeof (MonoString) + ((len + 1) * 2));
4248 /* overflow ? can't fit it, can't allocate it! */
4250 mono_gc_out_of_memory (-1);
4252 vtable = mono_class_vtable (domain, mono_defaults.string_class);
4254 s = mono_object_allocate_ptrfree (size, vtable);
4257 #if NEED_TO_ZERO_PTRFREE
4260 if (G_UNLIKELY (profile_allocs))
4261 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
4267 * mono_string_new_len:
4268 * @text: a pointer to an utf8 string
4269 * @length: number of bytes in @text to consider
4271 * Returns: A newly created string object which contains @text.
4274 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
4276 GError *error = NULL;
4277 MonoString *o = NULL;
4279 glong items_written;
4281 ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
4284 o = mono_string_new_utf16 (domain, ut, items_written);
4286 g_error_free (error);
4295 * @text: a pointer to an utf8 string
4297 * Returns: A newly created string object which contains @text.
4300 mono_string_new (MonoDomain *domain, const char *text)
4302 GError *error = NULL;
4303 MonoString *o = NULL;
4305 glong items_written;
4310 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
4313 o = mono_string_new_utf16 (domain, ut, items_written);
4315 g_error_free (error);
4318 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
4323 MonoString *o = NULL;
4325 if (!g_utf8_validate (text, -1, &end))
4328 len = g_utf8_strlen (text, -1);
4329 o = mono_string_new_size (domain, len);
4330 str = mono_string_chars (o);
4332 while (text < end) {
4333 *str++ = g_utf8_get_char (text);
4334 text = g_utf8_next_char (text);
4341 * mono_string_new_wrapper:
4342 * @text: pointer to utf8 characters.
4344 * Helper function to create a string object from @text in the current domain.
4347 mono_string_new_wrapper (const char *text)
4349 MonoDomain *domain = mono_domain_get ();
4351 MONO_ARCH_SAVE_REGS;
4354 return mono_string_new (domain, text);
4361 * @class: the class of the value
4362 * @value: a pointer to the unboxed data
4364 * Returns: A newly created object which contains @value.
4367 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
4373 g_assert (class->valuetype);
4374 if (mono_class_is_nullable (class))
4375 return mono_nullable_box (value, class);
4377 vtable = mono_class_vtable (domain, class);
4378 size = mono_class_instance_size (class);
4379 res = mono_object_new_alloc_specific (vtable);
4380 if (G_UNLIKELY (profile_allocs))
4381 mono_profiler_allocation (res, class);
4383 size = size - sizeof (MonoObject);
4386 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
4389 #if NO_UNALIGNED_ACCESS
4390 memcpy ((char *)res + sizeof (MonoObject), value, size);
4394 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
4397 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
4400 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
4403 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
4406 memcpy ((char *)res + sizeof (MonoObject), value, size);
4409 if (class->has_finalize)
4410 mono_object_register_finalizer (res);
4416 * @dest: destination pointer
4417 * @src: source pointer
4418 * @klass: a valuetype class
4420 * Copy a valuetype from @src to @dest. This function must be used
4421 * when @klass contains references fields.
4424 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
4426 int size = mono_class_value_size (klass, NULL);
4427 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
4428 memcpy (dest, src, size);
4432 * mono_value_copy_array:
4433 * @dest: destination array
4434 * @dest_idx: index in the @dest array
4435 * @src: source pointer
4436 * @count: number of items
4438 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
4439 * This function must be used when @klass contains references fields.
4440 * Overlap is handled.
4443 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
4445 int size = mono_array_element_size (dest->obj.vtable->klass);
4446 char *d = mono_array_addr_with_size (dest, size, dest_idx);
4447 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
4448 memmove (d, src, size * count);
4452 * mono_object_get_domain:
4453 * @obj: object to query
4455 * Returns: the MonoDomain where the object is hosted
4458 mono_object_get_domain (MonoObject *obj)
4460 return mono_object_domain (obj);
4464 * mono_object_get_class:
4465 * @obj: object to query
4467 * Returns: the MonOClass of the object.
4470 mono_object_get_class (MonoObject *obj)
4472 return mono_object_class (obj);
4475 * mono_object_get_size:
4476 * @o: object to query
4478 * Returns: the size, in bytes, of @o
4481 mono_object_get_size (MonoObject* o)
4483 MonoClass* klass = mono_object_class (o);
4484 if (klass == mono_defaults.string_class) {
4485 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
4486 } else if (o->vtable->rank) {
4487 MonoArray *array = (MonoArray*)o;
4488 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
4489 if (array->bounds) {
4492 size += sizeof (MonoArrayBounds) * o->vtable->rank;
4496 return mono_class_instance_size (klass);
4501 * mono_object_unbox:
4502 * @obj: object to unbox
4504 * Returns: a pointer to the start of the valuetype boxed in this
4507 * This method will assert if the object passed is not a valuetype.
4510 mono_object_unbox (MonoObject *obj)
4512 /* add assert for valuetypes? */
4513 g_assert (obj->vtable->klass->valuetype);
4514 return ((char*)obj) + sizeof (MonoObject);
4518 * mono_object_isinst:
4520 * @klass: a pointer to a class
4522 * Returns: @obj if @obj is derived from @klass
4525 mono_object_isinst (MonoObject *obj, MonoClass *klass)
4528 mono_class_init (klass);
4530 if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE)
4531 return mono_object_isinst_mbyref (obj, klass);
4536 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
4540 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
4549 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4550 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
4554 MonoClass *oklass = vt->klass;
4555 if ((oklass == mono_defaults.transparent_proxy_class))
4556 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
4558 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
4562 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
4564 MonoDomain *domain = mono_domain_get ();
4566 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
4567 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
4568 MonoMethod *im = NULL;
4571 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
4572 im = mono_object_get_virtual_method (rp, im);
4575 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
4578 res = mono_runtime_invoke (im, rp, pa, NULL);
4580 if (*(MonoBoolean *) mono_object_unbox(res)) {
4581 /* Update the vtable of the remote type, so it can safely cast to this new type */
4582 mono_upgrade_remote_class (domain, obj, klass);
4591 * mono_object_castclass_mbyref:
4593 * @klass: a pointer to a class
4595 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
4598 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
4600 if (!obj) return NULL;
4601 if (mono_object_isinst_mbyref (obj, klass)) return obj;
4603 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
4605 "InvalidCastException"));
4610 MonoDomain *orig_domain;
4616 str_lookup (MonoDomain *domain, gpointer user_data)
4618 LDStrInfo *info = user_data;
4619 if (info->res || domain == info->orig_domain)
4621 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
4627 mono_string_get_pinned (MonoString *str)
4631 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
4632 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
4633 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
4634 news->length = mono_string_length (str);
4639 #define mono_string_get_pinned(str) (str)
4643 mono_string_is_interned_lookup (MonoString *str, int insert)
4645 MonoGHashTable *ldstr_table;
4649 domain = ((MonoObject *)str)->vtable->domain;
4650 ldstr_table = domain->ldstr_table;
4652 if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
4657 str = mono_string_get_pinned (str);
4658 mono_g_hash_table_insert (ldstr_table, str, str);
4662 LDStrInfo ldstr_info;
4663 ldstr_info.orig_domain = domain;
4664 ldstr_info.ins = str;
4665 ldstr_info.res = NULL;
4667 mono_domain_foreach (str_lookup, &ldstr_info);
4668 if (ldstr_info.res) {
4670 * the string was already interned in some other domain:
4671 * intern it in the current one as well.
4673 mono_g_hash_table_insert (ldstr_table, str, str);
4683 * mono_string_is_interned:
4684 * @o: String to probe
4686 * Returns whether the string has been interned.
4689 mono_string_is_interned (MonoString *o)
4691 return mono_string_is_interned_lookup (o, FALSE);
4695 * mono_string_intern:
4696 * @o: String to intern
4698 * Interns the string passed.
4699 * Returns: The interned string.
4702 mono_string_intern (MonoString *str)
4704 return mono_string_is_interned_lookup (str, TRUE);
4709 * @domain: the domain where the string will be used.
4710 * @image: a metadata context
4711 * @idx: index into the user string table.
4713 * Implementation for the ldstr opcode.
4714 * Returns: a loaded string from the @image/@idx combination.
4717 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
4719 MONO_ARCH_SAVE_REGS;
4722 return mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
4724 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
4728 * mono_ldstr_metadata_sig
4729 * @domain: the domain for the string
4730 * @sig: the signature of a metadata string
4732 * Returns: a MonoString for a string stored in the metadata
4735 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
4737 const char *str = sig;
4738 MonoString *o, *interned;
4741 len2 = mono_metadata_decode_blob_size (str, &str);
4744 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
4745 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
4748 guint16 *p2 = (guint16*)mono_string_chars (o);
4749 for (i = 0; i < len2; ++i) {
4750 *p2 = GUINT16_FROM_LE (*p2);
4756 if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
4758 /* o will get garbage collected */
4762 o = mono_string_get_pinned (o);
4763 mono_g_hash_table_insert (domain->ldstr_table, o, o);
4770 * mono_string_to_utf8:
4771 * @s: a System.String
4773 * Return the UTF8 representation for @s.
4774 * the resulting buffer nedds to be freed with g_free().
4777 mono_string_to_utf8 (MonoString *s)
4781 GError *error = NULL;
4787 return g_strdup ("");
4789 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &error);
4791 MonoException *exc = mono_get_exception_argument ("string", error->message);
4792 g_error_free (error);
4793 mono_raise_exception(exc);
4795 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
4796 if (s->length > written) {
4797 /* allocate the total length and copy the part of the string that has been converted */
4798 char *as2 = g_malloc0 (s->length);
4799 memcpy (as2, as, written);
4808 * mono_string_to_utf16:
4811 * Return an null-terminated array of the utf-16 chars
4812 * contained in @s. The result must be freed with g_free().
4813 * This is a temporary helper until our string implementation
4814 * is reworked to always include the null terminating char.
4817 mono_string_to_utf16 (MonoString *s)
4824 as = g_malloc ((s->length * 2) + 2);
4825 as [(s->length * 2)] = '\0';
4826 as [(s->length * 2) + 1] = '\0';
4829 return (gunichar2 *)(as);
4832 memcpy (as, mono_string_chars(s), s->length * 2);
4833 return (gunichar2 *)(as);
4837 * mono_string_from_utf16:
4838 * @data: the UTF16 string (LPWSTR) to convert
4840 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
4842 * Returns: a MonoString.
4845 mono_string_from_utf16 (gunichar2 *data)
4847 MonoDomain *domain = mono_domain_get ();
4853 while (data [len]) len++;
4855 return mono_string_new_utf16 (domain, data, len);
4860 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s)
4867 return mono_string_to_utf8 (s);
4869 r = mono_string_to_utf8 (s);
4873 len = strlen (r) + 1;
4875 mp_s = mono_mempool_alloc (mp, len);
4877 mp_s = mono_image_alloc (image, len);
4879 memcpy (mp_s, r, len);
4887 * mono_string_to_utf8_image:
4888 * @s: a System.String
4890 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
4893 mono_string_to_utf8_image (MonoImage *image, MonoString *s)
4895 return mono_string_to_utf8_internal (NULL, image, s);
4899 * mono_string_to_utf8_mp:
4900 * @s: a System.String
4902 * Same as mono_string_to_utf8, but allocate the string from a mempool.
4905 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s)
4907 return mono_string_to_utf8_internal (mp, NULL, s);
4911 default_ex_handler (MonoException *ex)
4913 MonoObject *o = (MonoObject*)ex;
4914 g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
4918 static MonoExceptionFunc ex_handler = default_ex_handler;
4921 * mono_install_handler:
4922 * @func: exception handler
4924 * This is an internal JIT routine used to install the handler for exceptions
4928 mono_install_handler (MonoExceptionFunc func)
4930 ex_handler = func? func: default_ex_handler;
4934 * mono_raise_exception:
4935 * @ex: exception object
4937 * Signal the runtime that the exception @ex has been raised in unmanaged code.
4940 mono_raise_exception (MonoException *ex)
4943 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
4944 * that will cause gcc to omit the function epilog, causing problems when
4945 * the JIT tries to walk the stack, since the return address on the stack
4946 * will point into the next function in the executable, not this one.
4949 if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class) {
4950 MonoThread *thread = mono_thread_current ();
4951 g_assert (ex->object.vtable->domain == mono_domain_get ());
4952 MONO_OBJECT_SETREF (thread, abort_exc, ex);
4959 * mono_wait_handle_new:
4960 * @domain: Domain where the object will be created
4961 * @handle: Handle for the wait handle
4963 * Returns: A new MonoWaitHandle created in the given domain for the given handle
4966 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
4968 MonoWaitHandle *res;
4969 gpointer params [1];
4970 static MonoMethod *handle_set;
4972 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.waithandle_class);
4974 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
4976 handle_set = mono_class_get_property_from_name (mono_defaults.waithandle_class, "Handle")->set;
4978 params [0] = &handle;
4979 mono_runtime_invoke (handle_set, res, params, NULL);
4985 mono_wait_handle_get_handle (MonoWaitHandle *handle)
4987 static MonoClassField *f_os_handle;
4988 static MonoClassField *f_safe_handle;
4990 if (!f_os_handle && !f_safe_handle) {
4991 f_os_handle = mono_class_get_field_from_name (mono_defaults.waithandle_class, "os_handle");
4992 f_safe_handle = mono_class_get_field_from_name (mono_defaults.waithandle_class, "safe_wait_handle");
4997 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
5001 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
5008 mono_runtime_capture_context (MonoDomain *domain)
5010 RuntimeInvokeFunction runtime_invoke;
5012 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
5013 MonoMethod *method = mono_get_context_capture_method ();
5014 MonoMethod *wrapper;
5017 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
5018 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
5019 domain->capture_context_method = mono_compile_method (method);
5022 runtime_invoke = domain->capture_context_runtime_invoke;
5024 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
5027 * mono_async_result_new:
5028 * @domain:domain where the object will be created.
5029 * @handle: wait handle.
5030 * @state: state to pass to AsyncResult
5031 * @data: C closure data.
5033 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
5034 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
5038 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
5040 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
5041 MonoObject *context = mono_runtime_capture_context (domain);
5042 /* we must capture the execution context from the original thread */
5044 MONO_OBJECT_SETREF (res, execution_context, context);
5045 /* note: result may be null if the flow is suppressed */
5049 MONO_OBJECT_SETREF (res, object_data, object_data);
5050 MONO_OBJECT_SETREF (res, async_state, state);
5052 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
5054 res->sync_completed = FALSE;
5055 res->completed = FALSE;
5061 mono_message_init (MonoDomain *domain,
5062 MonoMethodMessage *this,
5063 MonoReflectionMethod *method,
5064 MonoArray *out_args)
5066 static MonoClass *object_array_klass;
5067 static MonoClass *byte_array_klass;
5068 static MonoClass *string_array_klass;
5069 MonoMethodSignature *sig = mono_method_signature (method->method);
5075 if (!object_array_klass) {
5078 klass = mono_array_class_get (mono_defaults.object_class, 1);
5081 mono_memory_barrier ();
5082 object_array_klass = klass;
5084 klass = mono_array_class_get (mono_defaults.byte_class, 1);
5087 mono_memory_barrier ();
5088 byte_array_klass = klass;
5090 klass = mono_array_class_get (mono_defaults.string_class, 1);
5093 mono_memory_barrier ();
5094 string_array_klass = klass;
5097 MONO_OBJECT_SETREF (this, method, method);
5099 MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
5100 MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
5101 this->async_result = NULL;
5102 this->call_type = CallType_Sync;
5104 names = g_new (char *, sig->param_count);
5105 mono_method_get_param_names (method->method, (const char **) names);
5106 MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
5108 for (i = 0; i < sig->param_count; i++) {
5109 name = mono_string_new (domain, names [i]);
5110 mono_array_setref (this->names, i, name);
5114 for (i = 0, j = 0; i < sig->param_count; i++) {
5115 if (sig->params [i]->byref) {
5117 MonoObject* arg = mono_array_get (out_args, gpointer, j);
5118 mono_array_setref (this->args, i, arg);
5122 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
5126 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
5129 mono_array_set (this->arg_types, guint8, i, arg_type);
5134 * mono_remoting_invoke:
5135 * @real_proxy: pointer to a RealProxy object
5136 * @msg: The MonoMethodMessage to execute
5137 * @exc: used to store exceptions
5138 * @out_args: used to store output arguments
5140 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
5141 * IMessage interface and it is not trivial to extract results from there. So
5142 * we call an helper method PrivateInvoke instead of calling
5143 * RealProxy::Invoke() directly.
5145 * Returns: the result object.
5148 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
5149 MonoObject **exc, MonoArray **out_args)
5151 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
5154 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
5157 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
5159 real_proxy->vtable->domain->private_invoke_method = im;
5162 pa [0] = real_proxy;
5167 return mono_runtime_invoke (im, NULL, pa, exc);
5171 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
5172 MonoObject **exc, MonoArray **out_args)
5174 static MonoClass *object_array_klass;
5177 MonoMethodSignature *sig;
5179 int i, j, outarg_count = 0;
5181 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5183 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
5184 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5185 target = tp->rp->unwrapped_server;
5187 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
5191 domain = mono_domain_get ();
5192 method = msg->method->method;
5193 sig = mono_method_signature (method);
5195 for (i = 0; i < sig->param_count; i++) {
5196 if (sig->params [i]->byref)
5200 if (!object_array_klass) {
5203 klass = mono_array_class_get (mono_defaults.object_class, 1);
5206 mono_memory_barrier ();
5207 object_array_klass = klass;
5210 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
5211 *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
5214 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
5216 for (i = 0, j = 0; i < sig->param_count; i++) {
5217 if (sig->params [i]->byref) {
5219 arg = mono_array_get (msg->args, gpointer, i);
5220 mono_array_setref (*out_args, j, arg);
5229 * mono_print_unhandled_exception:
5230 * @exc: The exception
5232 * Prints the unhandled exception.
5235 mono_print_unhandled_exception (MonoObject *exc)
5237 char *message = (char *) "";
5241 gboolean free_message = FALSE;
5243 if (mono_object_isinst (exc, mono_defaults.exception_class)) {
5244 klass = exc->vtable->klass;
5246 while (klass && method == NULL) {
5247 method = mono_class_get_method_from_name_flags (klass, "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
5249 klass = klass->parent;
5254 str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL);
5256 message = mono_string_to_utf8 (str);
5257 free_message = TRUE;
5262 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
5263 * exc->vtable->klass->name, message);
5265 g_printerr ("\nUnhandled Exception: %s\n", message);
5272 * mono_delegate_ctor:
5273 * @this: pointer to an uninitialized delegate object
5274 * @target: target object
5275 * @addr: pointer to native code
5278 * Initialize a delegate and sets a specific method, not the one
5279 * associated with addr. This is useful when sharing generic code.
5280 * In that case addr will most probably not be associated with the
5281 * correct instantiation of the method.
5284 mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer addr, MonoMethod *method)
5286 MonoDelegate *delegate = (MonoDelegate *)this;
5293 delegate->method = method;
5295 class = this->vtable->klass;
5296 mono_stats.delegate_creations++;
5298 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5300 method = mono_marshal_get_remoting_invoke (method);
5301 delegate->method_ptr = mono_compile_method (method);
5302 MONO_OBJECT_SETREF (delegate, target, target);
5303 } else if (mono_method_signature (method)->hasthis && method->klass->valuetype) {
5304 method = mono_marshal_get_unbox_wrapper (method);
5305 delegate->method_ptr = mono_compile_method (method);
5306 MONO_OBJECT_SETREF (delegate, target, target);
5308 delegate->method_ptr = addr;
5309 MONO_OBJECT_SETREF (delegate, target, target);
5312 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->klass);
5316 * mono_delegate_ctor:
5317 * @this: pointer to an uninitialized delegate object
5318 * @target: target object
5319 * @addr: pointer to native code
5321 * This is used to initialize a delegate.
5324 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
5326 MonoDomain *domain = mono_domain_get ();
5328 MonoMethod *method = NULL;
5332 if ((ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr)))) {
5333 method = ji->method;
5334 g_assert (!method->klass->generic_container);
5337 mono_delegate_ctor_with_method (this, target, addr, method);
5341 * mono_method_call_message_new:
5342 * @method: method to encapsulate
5343 * @params: parameters to the method
5344 * @invoke: optional, delegate invoke.
5345 * @cb: async callback delegate.
5346 * @state: state passed to the async callback.
5348 * Translates arguments pointers into a MonoMethodMessage.
5351 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
5352 MonoDelegate **cb, MonoObject **state)
5354 MonoDomain *domain = mono_domain_get ();
5355 MonoMethodSignature *sig = mono_method_signature (method);
5356 MonoMethodMessage *msg;
5359 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5362 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
5363 count = sig->param_count - 2;
5365 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
5366 count = sig->param_count;
5369 for (i = 0; i < count; i++) {
5374 if (sig->params [i]->byref)
5375 vpos = *((gpointer *)params [i]);
5379 type = sig->params [i]->type;
5380 class = mono_class_from_mono_type (sig->params [i]);
5382 if (class->valuetype)
5383 arg = mono_value_box (domain, class, vpos);
5385 arg = *((MonoObject **)vpos);
5387 mono_array_setref (msg->args, i, arg);
5390 if (cb != NULL && state != NULL) {
5391 *cb = *((MonoDelegate **)params [i]);
5393 *state = *((MonoObject **)params [i]);
5400 * mono_method_return_message_restore:
5402 * Restore results from message based processing back to arguments pointers
5405 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
5407 MonoMethodSignature *sig = mono_method_signature (method);
5408 int i, j, type, size, out_len;
5410 if (out_args == NULL)
5412 out_len = mono_array_length (out_args);
5416 for (i = 0, j = 0; i < sig->param_count; i++) {
5417 MonoType *pt = sig->params [i];
5422 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
5424 arg = mono_array_get (out_args, gpointer, j);
5428 case MONO_TYPE_VOID:
5429 g_assert_not_reached ();
5433 case MONO_TYPE_BOOLEAN:
5436 case MONO_TYPE_CHAR:
5443 case MONO_TYPE_VALUETYPE: {
5445 size = mono_class_value_size (((MonoObject*)arg)->vtable->klass, NULL);
5446 memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
5449 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
5450 memset (*((gpointer *)params [i]), 0, size);
5454 case MONO_TYPE_STRING:
5455 case MONO_TYPE_CLASS:
5456 case MONO_TYPE_ARRAY:
5457 case MONO_TYPE_SZARRAY:
5458 case MONO_TYPE_OBJECT:
5459 **((MonoObject ***)params [i]) = (MonoObject *)arg;
5462 g_assert_not_reached ();
5471 * mono_load_remote_field:
5472 * @this: pointer to an object
5473 * @klass: klass of the object containing @field
5474 * @field: the field to load
5475 * @res: a storage to store the result
5477 * This method is called by the runtime on attempts to load fields of
5478 * transparent proxy objects. @this points to such TP, @klass is the class of
5479 * the object containing @field. @res is a storage location which can be
5480 * used to store the result.
5482 * Returns: an address pointing to the value of field.
5485 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
5487 static MonoMethod *getter = NULL;
5488 MonoDomain *domain = mono_domain_get ();
5489 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5490 MonoClass *field_class;
5491 MonoMethodMessage *msg;
5492 MonoArray *out_args;
5496 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5497 g_assert (res != NULL);
5499 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5500 mono_field_get_value (tp->rp->unwrapped_server, field, res);
5505 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
5509 field_class = mono_class_from_mono_type (field->type);
5511 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5512 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
5513 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
5515 full_name = mono_type_get_full_name (klass);
5516 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5517 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5520 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5522 if (exc) mono_raise_exception ((MonoException *)exc);
5524 if (mono_array_length (out_args) == 0)
5527 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
5529 if (field_class->valuetype) {
5530 return ((char *)*res) + sizeof (MonoObject);
5536 * mono_load_remote_field_new:
5541 * Missing documentation.
5544 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
5546 static MonoMethod *getter = NULL;
5547 MonoDomain *domain = mono_domain_get ();
5548 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5549 MonoClass *field_class;
5550 MonoMethodMessage *msg;
5551 MonoArray *out_args;
5552 MonoObject *exc, *res;
5555 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5557 field_class = mono_class_from_mono_type (field->type);
5559 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5561 if (field_class->valuetype) {
5562 res = mono_object_new (domain, field_class);
5563 val = ((gchar *) res) + sizeof (MonoObject);
5567 mono_field_get_value (tp->rp->unwrapped_server, field, val);
5572 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
5576 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5577 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
5579 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
5581 full_name = mono_type_get_full_name (klass);
5582 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5583 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5586 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5588 if (exc) mono_raise_exception ((MonoException *)exc);
5590 if (mono_array_length (out_args) == 0)
5593 res = mono_array_get (out_args, MonoObject *, 0);
5599 * mono_store_remote_field:
5600 * @this: pointer to an object
5601 * @klass: klass of the object containing @field
5602 * @field: the field to load
5603 * @val: the value/object to store
5605 * This method is called by the runtime on attempts to store fields of
5606 * transparent proxy objects. @this points to such TP, @klass is the class of
5607 * the object containing @field. @val is the new value to store in @field.
5610 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
5612 static MonoMethod *setter = NULL;
5613 MonoDomain *domain = mono_domain_get ();
5614 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5615 MonoClass *field_class;
5616 MonoMethodMessage *msg;
5617 MonoArray *out_args;
5622 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5624 field_class = mono_class_from_mono_type (field->type);
5626 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5627 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
5628 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
5633 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
5637 if (field_class->valuetype)
5638 arg = mono_value_box (domain, field_class, val);
5640 arg = *((MonoObject **)val);
5643 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5644 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
5646 full_name = mono_type_get_full_name (klass);
5647 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5648 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5649 mono_array_setref (msg->args, 2, arg);
5652 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5654 if (exc) mono_raise_exception ((MonoException *)exc);
5658 * mono_store_remote_field_new:
5664 * Missing documentation
5667 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
5669 static MonoMethod *setter = NULL;
5670 MonoDomain *domain = mono_domain_get ();
5671 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5672 MonoClass *field_class;
5673 MonoMethodMessage *msg;
5674 MonoArray *out_args;
5678 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5680 field_class = mono_class_from_mono_type (field->type);
5682 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5683 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
5684 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
5689 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
5693 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5694 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
5696 full_name = mono_type_get_full_name (klass);
5697 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5698 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5699 mono_array_setref (msg->args, 2, arg);
5702 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5704 if (exc) mono_raise_exception ((MonoException *)exc);
5708 * mono_create_ftnptr:
5710 * Given a function address, create a function descriptor for it.
5711 * This is only needed on IA64 and PPC64.
5714 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
5719 desc = mono_domain_code_reserve (domain, 2 * sizeof (gpointer));
5725 #elif defined(__ppc64__) || defined(__powerpc64__)
5728 desc = mono_domain_code_reserve (domain, 3 * sizeof (gpointer));
5741 * mono_get_addr_from_ftnptr:
5743 * Given a pointer to a function descriptor, return the function address.
5744 * This is only needed on IA64 and PPC64.
5747 mono_get_addr_from_ftnptr (gpointer descr)
5749 #if defined(__ia64__) || defined(__ppc64__) || defined(__powerpc64__)
5750 return *(gpointer*)descr;
5758 * mono_string_chars:
5761 * Returns a pointer to the UCS16 characters stored in the MonoString
5764 mono_string_chars(MonoString *s)
5766 /* This method is here only for documentation extraction, this is a macro */
5770 * mono_string_length:
5773 * Returns the lenght in characters of the string
5776 mono_string_length (MonoString *s)
5778 /* This method is here only for documentation extraction, this is a macro */