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 MonoImtThunkBuilder imt_thunk_builder = NULL;
471 #define ARCH_USE_IMT (imt_thunk_builder != NULL)
472 #if (MONO_IMT_SIZE > 32)
473 #error "MONO_IMT_SIZE cannot be larger than 32"
477 mono_install_trampoline (MonoTrampoline func)
479 arch_create_jit_trampoline = func? func: default_trampoline;
483 mono_install_jump_trampoline (MonoJumpTrampoline func)
485 arch_create_jump_trampoline = func? func: default_jump_trampoline;
489 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
491 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
495 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
497 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
501 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
502 imt_thunk_builder = func;
505 static MonoCompileFunc default_mono_compile_method = NULL;
508 * mono_install_compile_method:
509 * @func: function to install
511 * This is a VM internal routine
514 mono_install_compile_method (MonoCompileFunc func)
516 default_mono_compile_method = func;
520 * mono_compile_method:
521 * @method: The method to compile.
523 * This JIT-compiles the method, and returns the pointer to the native code
527 mono_compile_method (MonoMethod *method)
529 if (!default_mono_compile_method) {
530 g_error ("compile method called on uninitialized runtime");
533 return default_mono_compile_method (method);
537 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
539 return arch_create_jump_trampoline (domain, method, add_sync_wrapper);
543 mono_runtime_create_delegate_trampoline (MonoClass *klass)
545 return arch_create_delegate_trampoline (klass);
548 static MonoFreeMethodFunc default_mono_free_method = NULL;
551 * mono_install_free_method:
552 * @func: pointer to the MonoFreeMethodFunc used to release a method
554 * This is an internal VM routine, it is used for the engines to
555 * register a handler to release the resources associated with a method.
557 * Methods are freed when no more references to the delegate that holds
561 mono_install_free_method (MonoFreeMethodFunc func)
563 default_mono_free_method = func;
567 * mono_runtime_free_method:
568 * @domain; domain where the method is hosted
569 * @method: method to release
571 * This routine is invoked to free the resources associated with
572 * a method that has been JIT compiled. This is used to discard
573 * methods that were used only temporarily (for example, used in marshalling)
577 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
579 if (default_mono_free_method != NULL)
580 default_mono_free_method (domain, method);
582 mono_method_clear_object (domain, method);
584 mono_free_method (method);
588 * The vtables in the root appdomain are assumed to be reachable by other
589 * roots, and we don't use typed allocation in the other domains.
592 /* The sync block is no longer a GC pointer */
593 #define GC_HEADER_BITMAP (0)
595 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
598 compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
600 MonoClassField *field;
606 max_size = mono_class_data_size (class) / sizeof (gpointer);
608 max_size = class->instance_size / sizeof (gpointer);
609 if (max_size >= size) {
610 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
613 for (p = class; p != NULL; p = p->parent) {
614 gpointer iter = NULL;
615 while ((field = mono_class_get_fields (p, &iter))) {
619 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
621 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
624 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
627 /* FIXME: should not happen, flag as type load error */
628 if (field->type->byref)
631 if (static_fields && field->offset == -1)
635 pos = field->offset / sizeof (gpointer);
638 type = mono_type_get_underlying_type (field->type);
639 switch (type->type) {
642 case MONO_TYPE_FNPTR:
644 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
649 if (class->image != mono_defaults.corlib)
652 case MONO_TYPE_STRING:
653 case MONO_TYPE_SZARRAY:
654 case MONO_TYPE_CLASS:
655 case MONO_TYPE_OBJECT:
656 case MONO_TYPE_ARRAY:
657 g_assert ((field->offset % sizeof(gpointer)) == 0);
659 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
660 *max_set = MAX (*max_set, pos);
662 case MONO_TYPE_GENERICINST:
663 if (!mono_type_generic_inst_is_valuetype (type)) {
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);
672 case MONO_TYPE_VALUETYPE: {
673 MonoClass *fclass = mono_class_from_mono_type (field->type);
674 if (fclass->has_references) {
675 /* remove the object header */
676 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
690 case MONO_TYPE_BOOLEAN:
694 g_assert_not_reached ();
706 * similar to the above, but sets the bits in the bitmap for any non-ref field
707 * and ignores static fields
710 compute_class_non_ref_bitmap (MonoClass *class, gsize *bitmap, int size, int offset)
712 MonoClassField *field;
717 max_size = class->instance_size / sizeof (gpointer);
718 if (max_size >= size) {
719 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
722 for (p = class; p != NULL; p = p->parent) {
723 gpointer iter = NULL;
724 while ((field = mono_class_get_fields (p, &iter))) {
727 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
729 /* FIXME: should not happen, flag as type load error */
730 if (field->type->byref)
733 pos = field->offset / sizeof (gpointer);
736 type = mono_type_get_underlying_type (field->type);
737 switch (type->type) {
738 #if SIZEOF_VOID_P == 8
742 case MONO_TYPE_FNPTR:
747 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
748 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
749 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
752 #if SIZEOF_VOID_P == 4
756 case MONO_TYPE_FNPTR:
761 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
762 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
763 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
769 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
770 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
771 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
774 case MONO_TYPE_BOOLEAN:
777 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
779 case MONO_TYPE_STRING:
780 case MONO_TYPE_SZARRAY:
781 case MONO_TYPE_CLASS:
782 case MONO_TYPE_OBJECT:
783 case MONO_TYPE_ARRAY:
785 case MONO_TYPE_GENERICINST:
786 if (!mono_type_generic_inst_is_valuetype (type)) {
791 case MONO_TYPE_VALUETYPE: {
792 MonoClass *fclass = mono_class_from_mono_type (field->type);
793 /* remove the object header */
794 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
798 g_assert_not_reached ();
807 * mono_class_insecure_overlapping:
808 * check if a class with explicit layout has references and non-references
809 * fields overlapping.
811 * Returns: TRUE if it is insecure to load the type.
814 mono_class_insecure_overlapping (MonoClass *klass)
818 gsize default_bitmap [4] = {0};
820 gsize default_nrbitmap [4] = {0};
821 int i, insecure = FALSE;
824 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
825 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
827 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
828 int idx = i % (sizeof (bitmap [0]) * 8);
829 if (bitmap [idx] & nrbitmap [idx]) {
834 if (bitmap != default_bitmap)
836 if (nrbitmap != default_nrbitmap)
839 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
847 mono_string_alloc (int length)
849 return mono_string_new_size (mono_domain_get (), length);
853 mono_class_compute_gc_descriptor (MonoClass *class)
857 gsize default_bitmap [4] = {0};
858 static gboolean gcj_inited = FALSE;
863 mono_register_jit_icall (mono_object_new_ptrfree, "mono_object_new_ptrfree", mono_create_icall_signature ("object ptr"), FALSE);
864 mono_register_jit_icall (mono_object_new_ptrfree_box, "mono_object_new_ptrfree_box", mono_create_icall_signature ("object ptr"), FALSE);
865 mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
866 mono_register_jit_icall (mono_string_alloc, "mono_string_alloc", mono_create_icall_signature ("object int"), FALSE);
868 #ifdef HAVE_GC_GCJ_MALLOC
870 * This is not needed unless the relevant code in mono_get_allocation_ftn () is
874 #ifdef GC_REDIRECT_TO_LOCAL
875 mono_register_jit_icall (GC_local_gcj_malloc, "GC_local_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
876 mono_register_jit_icall (GC_local_gcj_fast_malloc, "GC_local_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
878 mono_register_jit_icall (GC_gcj_malloc, "GC_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
879 mono_register_jit_icall (GC_gcj_fast_malloc, "GC_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
884 mono_loader_unlock ();
888 mono_class_init (class);
890 if (class->gc_descr_inited)
893 class->gc_descr_inited = TRUE;
894 class->gc_descr = GC_NO_DESCRIPTOR;
896 bitmap = default_bitmap;
897 if (class == mono_defaults.string_class) {
898 class->gc_descr = (gpointer)mono_gc_make_descr_for_string (bitmap, 2);
899 } else if (class->rank) {
900 mono_class_compute_gc_descriptor (class->element_class);
901 if (!class->element_class->valuetype) {
903 class->gc_descr = mono_gc_make_descr_for_array (TRUE, &abm, 1, sizeof (gpointer));
904 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
905 class->name_space, class->name);*/
907 /* remove the object header */
908 bitmap = compute_class_bitmap (class->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
909 class->gc_descr = mono_gc_make_descr_for_array (TRUE, bitmap, mono_array_element_size (class) / sizeof (gpointer), mono_array_element_size (class));
910 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
911 class->name_space, class->name);*/
912 if (bitmap != default_bitmap)
916 /*static int count = 0;
919 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
920 class->gc_descr = (gpointer)mono_gc_make_descr_for_object (bitmap, max_set + 1, class->instance_size);
922 if (class->gc_descr == GC_NO_DESCRIPTOR)
923 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
925 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
926 if (bitmap != default_bitmap)
932 * field_is_special_static:
933 * @fklass: The MonoClass to look up.
934 * @field: The MonoClassField describing the field.
936 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
937 * SPECIAL_STATIC_NONE otherwise.
940 field_is_special_static (MonoClass *fklass, MonoClassField *field)
942 MonoCustomAttrInfo *ainfo;
944 ainfo = mono_custom_attrs_from_field (fklass, field);
947 for (i = 0; i < ainfo->num_attrs; ++i) {
948 MonoClass *klass = ainfo->attrs [i].ctor->klass;
949 if (klass->image == mono_defaults.corlib) {
950 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
951 mono_custom_attrs_free (ainfo);
952 return SPECIAL_STATIC_THREAD;
954 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
955 mono_custom_attrs_free (ainfo);
956 return SPECIAL_STATIC_CONTEXT;
960 mono_custom_attrs_free (ainfo);
961 return SPECIAL_STATIC_NONE;
964 static gpointer imt_trampoline = NULL;
967 mono_install_imt_trampoline (gpointer tramp_code)
969 imt_trampoline = tramp_code;
972 static gpointer vtable_trampoline = NULL;
975 mono_install_vtable_trampoline (gpointer tramp_code)
977 vtable_trampoline = tramp_code;
980 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
981 #define mix(a,b,c) { \
982 a -= c; a ^= rot(c, 4); c += b; \
983 b -= a; b ^= rot(a, 6); a += c; \
984 c -= b; c ^= rot(b, 8); b += a; \
985 a -= c; a ^= rot(c,16); c += b; \
986 b -= a; b ^= rot(a,19); a += c; \
987 c -= b; c ^= rot(b, 4); b += a; \
989 #define final(a,b,c) { \
990 c ^= b; c -= rot(b,14); \
991 a ^= c; a -= rot(c,11); \
992 b ^= a; b -= rot(a,25); \
993 c ^= b; c -= rot(b,16); \
994 a ^= c; a -= rot(c,4); \
995 b ^= a; b -= rot(a,14); \
996 c ^= b; c -= rot(b,24); \
1000 mono_method_get_imt_slot (MonoMethod *method)
1002 MonoMethodSignature *sig;
1004 guint32 *hashes_start, *hashes;
1008 /* This can be used to stress tests the collision code */
1012 * We do this to simplify generic sharing. It will hurt
1013 * performance in cases where a class implements two different
1014 * instantiations of the same generic interface.
1015 * The code in build_imt_slots () depends on this.
1017 if (method->is_inflated)
1018 method = ((MonoMethodInflated*)method)->declaring;
1020 sig = mono_method_signature (method);
1021 hashes_count = sig->param_count + 4;
1022 hashes_start = malloc (hashes_count * sizeof (guint32));
1023 hashes = hashes_start;
1025 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1026 printf ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod\n",
1027 method->klass->name_space, method->klass->name, method->name);
1028 g_assert_not_reached ();
1031 /* Initialize hashes */
1032 hashes [0] = g_str_hash (method->klass->name);
1033 hashes [1] = g_str_hash (method->klass->name_space);
1034 hashes [2] = g_str_hash (method->name);
1035 hashes [3] = mono_metadata_type_hash (sig->ret);
1036 for (i = 0; i < sig->param_count; i++) {
1037 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1040 /* Setup internal state */
1041 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1043 /* Handle most of the hashes */
1044 while (hashes_count > 3) {
1053 /* Handle the last 3 hashes (all the case statements fall through) */
1054 switch (hashes_count) {
1055 case 3 : c += hashes [2];
1056 case 2 : b += hashes [1];
1057 case 1 : a += hashes [0];
1059 case 0: /* nothing left to add */
1063 free (hashes_start);
1064 /* Report the result */
1065 return c % MONO_IMT_SIZE;
1074 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1075 guint32 imt_slot = mono_method_get_imt_slot (method);
1076 MonoImtBuilderEntry *entry;
1078 if (slot_num >= 0 && imt_slot != slot_num) {
1079 /* we build just a single imt slot and this is not it */
1083 entry = g_malloc0 (sizeof (MonoImtBuilderEntry));
1084 entry->key = method;
1085 entry->value.vtable_slot = vtable_slot;
1086 entry->next = imt_builder [imt_slot];
1087 if (imt_builder [imt_slot] != NULL) {
1088 entry->children = imt_builder [imt_slot]->children + 1;
1089 if (entry->children == 1) {
1090 mono_stats.imt_slots_with_collisions++;
1091 *imt_collisions_bitmap |= (1 << imt_slot);
1094 entry->children = 0;
1095 mono_stats.imt_used_slots++;
1097 imt_builder [imt_slot] = entry;
1099 printf ("Added IMT slot for method (%p) %s.%s.%s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1100 method, method->klass->name_space, method->klass->name,
1101 method->name, imt_slot, vtable_slot, entry->children);
1107 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1109 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1113 e->method->klass->name_space,
1114 e->method->klass->name,
1117 printf (" * %s: NULL\n", message);
1123 compare_imt_builder_entries (const void *p1, const void *p2) {
1124 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1125 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1127 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1131 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1133 int count = end - start;
1134 int chunk_start = out_array->len;
1137 for (i = start; i < end; ++i) {
1138 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1139 item->key = sorted_array [i]->key;
1140 item->value = sorted_array [i]->value;
1141 item->has_target_code = sorted_array [i]->has_target_code;
1142 item->is_equals = TRUE;
1144 item->check_target_idx = out_array->len + 1;
1146 item->check_target_idx = 0;
1147 g_ptr_array_add (out_array, item);
1150 int middle = start + count / 2;
1151 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1153 item->key = sorted_array [middle]->key;
1154 item->is_equals = FALSE;
1155 g_ptr_array_add (out_array, item);
1156 imt_emit_ir (sorted_array, start, middle, out_array);
1157 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1163 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1164 int number_of_entries = entries->children + 1;
1165 MonoImtBuilderEntry **sorted_array = malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1166 GPtrArray *result = g_ptr_array_new ();
1167 MonoImtBuilderEntry *current_entry;
1170 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1171 sorted_array [i] = current_entry;
1173 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1175 /*for (i = 0; i < number_of_entries; i++) {
1176 print_imt_entry (" sorted array:", sorted_array [i], i);
1179 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1181 free (sorted_array);
1186 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1188 if (imt_builder_entry != NULL) {
1189 if (imt_builder_entry->children == 0 && !fail_tramp) {
1190 /* No collision, return the vtable slot contents */
1191 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1193 /* Collision, build the thunk */
1194 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1197 result = imt_thunk_builder (vtable, domain,
1198 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1199 for (i = 0; i < imt_ir->len; ++i)
1200 g_free (g_ptr_array_index (imt_ir, i));
1201 g_ptr_array_free (imt_ir, TRUE);
1213 static MonoImtBuilderEntry*
1214 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1217 * LOCKING: requires the loader and domain locks.
1221 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1225 guint32 imt_collisions_bitmap = 0;
1226 MonoImtBuilderEntry **imt_builder = calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1227 int method_count = 0;
1228 gboolean record_method_count_for_max_collisions = FALSE;
1229 gboolean has_generic_virtual = FALSE;
1232 printf ("Building IMT for class %s.%s\n", klass->name_space, klass->name);
1234 for (i = 0; i < klass->interface_offsets_count; ++i) {
1235 MonoClass *iface = klass->interfaces_packed [i];
1236 int interface_offset = klass->interface_offsets_packed [i];
1237 int method_slot_in_interface;
1238 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1241 if (slot_num >= 0 && iface->is_inflated) {
1243 * The imt slot of the method is the same as for its declaring method,
1244 * see the comment in mono_method_get_imt_slot (), so we can
1245 * avoid inflating methods which will be discarded by
1246 * add_imt_builder_entry anyway.
1248 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1249 if (mono_method_get_imt_slot (method) != slot_num)
1252 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1253 if (method->is_generic) {
1254 has_generic_virtual = TRUE;
1257 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1260 if (extra_interfaces) {
1261 int interface_offset = klass->vtable_size;
1263 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1264 MonoClass* iface = list_item->data;
1265 int method_slot_in_interface;
1266 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1267 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1268 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1270 interface_offset += iface->method.count;
1273 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1274 /* overwrite the imt slot only if we're building all the entries or if
1275 * we're building this specific one
1277 if (slot_num < 0 || i == slot_num) {
1278 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1281 if (imt_builder [i]) {
1282 MonoImtBuilderEntry *entry;
1284 /* Link entries with imt_builder [i] */
1285 for (entry = entries; entry->next; entry = entry->next)
1287 entry->next = imt_builder [i];
1288 entries->children += imt_builder [i]->children + 1;
1290 imt_builder [i] = entries;
1293 if (has_generic_virtual) {
1295 * There might be collisions later when the the thunk is expanded.
1297 imt_collisions_bitmap |= (1 << i);
1300 * The IMT thunk might be called with an instance of one of the
1301 * generic virtual methods, so has to fallback to the IMT trampoline.
1303 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], imt_trampoline);
1305 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1309 printf ("initialize_imt_slot[%d]: %p\n", i, imt [i]);
1311 if (imt_builder [i] != NULL) {
1312 int methods_in_slot = imt_builder [i]->children + 1;
1313 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1314 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1315 record_method_count_for_max_collisions = TRUE;
1317 method_count += methods_in_slot;
1321 mono_stats.imt_number_of_methods += method_count;
1322 if (record_method_count_for_max_collisions) {
1323 mono_stats.imt_method_count_when_max_collisions = method_count;
1326 for (i = 0; i < MONO_IMT_SIZE; i++) {
1327 MonoImtBuilderEntry* entry = imt_builder [i];
1328 while (entry != NULL) {
1329 MonoImtBuilderEntry* next = entry->next;
1335 /* we OR the bitmap since we may build just a single imt slot at a time */
1336 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1340 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1341 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1345 * mono_vtable_build_imt_slot:
1346 * @vtable: virtual object table struct
1347 * @imt_slot: slot in the IMT table
1349 * Fill the given @imt_slot in the IMT table of @vtable with
1350 * a trampoline or a thunk for the case of collisions.
1351 * This is part of the internal mono API.
1353 * LOCKING: Take the domain lock.
1356 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1358 gpointer *imt = (gpointer*)vtable;
1359 imt -= MONO_IMT_SIZE;
1360 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1362 /* no support for extra interfaces: the proxy objects will need
1363 * to build the complete IMT
1364 * Update and heck needs to ahppen inside the proper domain lock, as all
1365 * the changes made to a MonoVTable.
1367 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1368 mono_domain_lock (vtable->domain);
1369 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1370 if (imt [imt_slot] == imt_trampoline)
1371 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1372 mono_domain_unlock (vtable->domain);
1373 mono_loader_unlock ();
1378 * The first two free list entries both belong to the wait list: The
1379 * first entry is the pointer to the head of the list and the second
1380 * entry points to the last element. That way appending and removing
1381 * the first element are both O(1) operations.
1383 #define NUM_FREE_LISTS 12
1384 #define FIRST_FREE_LIST_SIZE 64
1385 #define MAX_WAIT_LENGTH 50
1386 #define THUNK_THRESHOLD 10
1389 * LOCKING: The domain lock must be held.
1392 init_thunk_free_lists (MonoDomain *domain)
1394 if (domain->thunk_free_lists)
1396 domain->thunk_free_lists = mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1400 list_index_for_size (int item_size)
1403 int size = FIRST_FREE_LIST_SIZE;
1405 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1414 * mono_method_alloc_generic_virtual_thunk:
1416 * @size: size in bytes
1418 * Allocs size bytes to be used for the code of a generic virtual
1419 * thunk. It's either allocated from the domain's code manager or
1420 * reused from a previously invalidated piece.
1422 * LOCKING: The domain lock must be held.
1425 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1427 static gboolean inited = FALSE;
1428 static int generic_virtual_thunks_size = 0;
1432 MonoThunkFreeList **l;
1434 init_thunk_free_lists (domain);
1436 size += sizeof (guint32);
1437 if (size < sizeof (MonoThunkFreeList))
1438 size = sizeof (MonoThunkFreeList);
1440 i = list_index_for_size (size);
1441 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1442 if ((*l)->size >= size) {
1443 MonoThunkFreeList *item = *l;
1445 return ((guint32*)item) + 1;
1449 /* no suitable item found - search lists of larger sizes */
1450 while (++i < NUM_FREE_LISTS) {
1451 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1454 g_assert (item->size > size);
1455 domain->thunk_free_lists [i] = item->next;
1456 return ((guint32*)item) + 1;
1459 /* still nothing found - allocate it */
1461 mono_counters_register ("Generic virtual thunk bytes",
1462 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1465 generic_virtual_thunks_size += size;
1467 p = mono_domain_code_reserve (domain, size);
1474 * LOCKING: The domain lock must be held.
1477 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1480 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1482 init_thunk_free_lists (domain);
1484 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1485 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1486 int length = item->length;
1489 /* unlink the first item from the wait list */
1490 domain->thunk_free_lists [0] = item->next;
1491 domain->thunk_free_lists [0]->length = length - 1;
1493 i = list_index_for_size (item->size);
1495 /* put it in the free list */
1496 item->next = domain->thunk_free_lists [i];
1497 domain->thunk_free_lists [i] = item;
1501 if (domain->thunk_free_lists [1]) {
1502 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1503 domain->thunk_free_lists [0]->length++;
1505 g_assert (!domain->thunk_free_lists [0]);
1507 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1508 domain->thunk_free_lists [0]->length = 1;
1512 typedef struct _GenericVirtualCase {
1516 struct _GenericVirtualCase *next;
1517 } GenericVirtualCase;
1520 * get_generic_virtual_entries:
1522 * Return IMT entries for the generic virtual method instances for vtable slot
1525 static MonoImtBuilderEntry*
1526 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1528 GenericVirtualCase *list;
1529 MonoImtBuilderEntry *entries;
1531 mono_domain_lock (domain);
1532 if (!domain->generic_virtual_cases)
1533 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1535 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1538 for (; list; list = list->next) {
1539 MonoImtBuilderEntry *entry;
1541 if (list->count < THUNK_THRESHOLD)
1544 entry = g_new0 (MonoImtBuilderEntry, 1);
1545 entry->key = list->method;
1546 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1547 entry->has_target_code = 1;
1549 entry->children = entries->children + 1;
1550 entry->next = entries;
1554 mono_domain_unlock (domain);
1556 /* FIXME: Leaking memory ? */
1561 * mono_method_add_generic_virtual_invocation:
1563 * @vtable_slot: pointer to the vtable slot
1564 * @method: the inflated generic virtual method
1565 * @code: the method's code
1567 * Registers a call via unmanaged code to a generic virtual method
1568 * instantiation. If the number of calls reaches a threshold
1569 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1570 * virtual method thunk.
1573 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1574 gpointer *vtable_slot,
1575 MonoMethod *method, gpointer code)
1577 static gboolean inited = FALSE;
1578 static int num_added = 0;
1580 GenericVirtualCase *gvc, *list;
1581 MonoImtBuilderEntry *entries;
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 ((gpointer)vtable_slot < (gpointer)vtable)
1619 /* Force the rebuild of the thunk at the next call */
1620 *vtable_slot = imt_trampoline;
1622 entries = get_generic_virtual_entries (domain, vtable_slot);
1624 sorted = imt_sort_slot_entries (entries);
1626 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1630 MonoImtBuilderEntry *next = entries->next;
1635 for (i = 0; i < sorted->len; ++i)
1636 g_free (g_ptr_array_index (sorted, i));
1637 g_ptr_array_free (sorted, TRUE);
1640 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1641 invalidate_generic_virtual_thunk (domain, old_thunk);
1644 mono_domain_unlock (domain);
1647 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class);
1650 * mono_class_vtable:
1651 * @domain: the application domain
1652 * @class: the class to initialize
1654 * VTables are domain specific because we create domain specific code, and
1655 * they contain the domain specific static class data.
1656 * On failure, NULL is returned, and class->exception_type is set.
1659 mono_class_vtable (MonoDomain *domain, MonoClass *class)
1661 MonoClassRuntimeInfo *runtime_info;
1665 /* this check can be inlined in jitted code, too */
1666 runtime_info = class->runtime_info;
1667 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1668 return runtime_info->domain_vtables [domain->domain_id];
1669 if (class->exception_type)
1671 return mono_class_create_runtime_vtable (domain, class);
1675 * mono_class_try_get_vtable:
1676 * @domain: the application domain
1677 * @class: the class to initialize
1679 * This function tries to get the associated vtable from @class if
1680 * it was already created.
1683 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *class)
1685 MonoClassRuntimeInfo *runtime_info;
1689 runtime_info = class->runtime_info;
1690 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1691 return runtime_info->domain_vtables [domain->domain_id];
1696 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class)
1699 MonoClassRuntimeInfo *runtime_info, *old_info;
1700 MonoClassField *field;
1703 int imt_table_bytes = 0;
1704 guint32 vtable_size, class_size;
1707 gpointer *interface_offsets;
1709 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1710 mono_domain_lock (domain);
1711 runtime_info = class->runtime_info;
1712 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1713 mono_domain_unlock (domain);
1714 mono_loader_unlock ();
1715 return runtime_info->domain_vtables [domain->domain_id];
1717 if (!class->inited || class->exception_type) {
1718 if (!mono_class_init (class) || class->exception_type){
1720 mono_domain_unlock (domain);
1721 mono_loader_unlock ();
1722 exc = mono_class_get_exception_for_failure (class);
1724 mono_raise_exception (exc);
1728 mono_class_init (class);
1731 * For some classes, mono_class_init () already computed class->vtable_size, and
1732 * that is all that is needed because of the vtable trampolines.
1734 if (!class->vtable_size)
1735 mono_class_setup_vtable (class);
1737 if (class->exception_type) {
1738 mono_domain_unlock (domain);
1739 mono_loader_unlock ();
1744 vtable_size = sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
1745 if (class->interface_offsets_count) {
1746 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1747 vtable_size += sizeof (gpointer) * (MONO_IMT_SIZE);
1748 mono_stats.imt_number_of_tables++;
1749 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
1752 vtable_size = sizeof (gpointer) * (class->max_interface_id + 1) +
1753 sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
1756 mono_stats.used_class_count++;
1757 mono_stats.class_vtable_size += vtable_size;
1758 interface_offsets = mono_domain_alloc0 (domain, vtable_size);
1761 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1763 vt = (MonoVTable*) (interface_offsets + class->max_interface_id + 1);
1765 vt->rank = class->rank;
1766 vt->domain = domain;
1768 mono_class_compute_gc_descriptor (class);
1770 * We can't use typed allocation in the non-root domains, since the
1771 * collector needs the GC descriptor stored in the vtable even after
1772 * the mempool containing the vtable is destroyed when the domain is
1773 * unloaded. An alternative might be to allocate vtables in the GC
1774 * heap, but this does not seem to work (it leads to crashes inside
1775 * libgc). If that approach is tried, two gc descriptors need to be
1776 * allocated for each class: one for the root domain, and one for all
1777 * other domains. The second descriptor should contain a bit for the
1778 * vtable field in MonoObject, since we can no longer assume the
1779 * vtable is reachable by other roots after the appdomain is unloaded.
1781 #ifdef HAVE_BOEHM_GC
1782 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1783 vt->gc_descr = GC_NO_DESCRIPTOR;
1786 vt->gc_descr = class->gc_descr;
1788 if ((class_size = mono_class_data_size (class))) {
1789 if (class->has_static_refs) {
1790 gpointer statics_gc_descr;
1792 gsize default_bitmap [4] = {0};
1795 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1796 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
1797 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1798 vt->data = mono_gc_alloc_fixed (class_size, statics_gc_descr);
1799 mono_domain_add_class_static_data (domain, class, vt->data, NULL);
1800 if (bitmap != default_bitmap)
1803 vt->data = mono_domain_alloc0 (domain, class_size);
1805 mono_stats.class_static_data_size += class_size;
1810 while ((field = mono_class_get_fields (class, &iter))) {
1811 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1813 if (mono_field_is_deleted (field))
1815 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1816 gint32 special_static = class->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (class, field);
1817 if (special_static != SPECIAL_STATIC_NONE) {
1818 guint32 size, offset;
1820 size = mono_type_size (field->type, &align);
1821 offset = mono_alloc_special_static_data (special_static, size, align);
1822 if (!domain->special_static_fields)
1823 domain->special_static_fields = g_hash_table_new (NULL, NULL);
1824 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
1826 * This marks the field as special static to speed up the
1827 * checks in mono_field_static_get/set_value ().
1833 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
1834 MonoClass *fklass = mono_class_from_mono_type (field->type);
1835 const char *data = mono_field_get_data (field);
1837 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
1838 t = (char*)vt->data + field->offset;
1839 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
1842 if (fklass->valuetype) {
1843 memcpy (t, data, mono_class_value_size (fklass, NULL));
1845 /* it's a pointer type: add check */
1846 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
1853 vt->max_interface_id = class->max_interface_id;
1854 vt->interface_bitmap = class->interface_bitmap;
1856 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
1857 // class->name, class->interface_offsets_count);
1859 if (! ARCH_USE_IMT) {
1860 /* initialize interface offsets */
1861 for (i = 0; i < class->interface_offsets_count; ++i) {
1862 int interface_id = class->interfaces_packed [i]->interface_id;
1863 int slot = class->interface_offsets_packed [i];
1864 interface_offsets [class->max_interface_id - interface_id] = &(vt->vtable [slot]);
1868 /* FIXME: class_vtable_hash is basically obsolete now: remove as soon
1869 * as we change the code in appdomain.c to invalidate vtables by
1870 * looking at the possible MonoClasses created for the domain.
1872 g_hash_table_insert (domain->class_vtable_hash, class, vt);
1873 /* class->runtime_info is protected by the loader lock, both when
1874 * it it enlarged and when it is stored info.
1877 old_info = class->runtime_info;
1878 if (old_info && old_info->max_domain >= domain->domain_id) {
1879 /* someone already created a large enough runtime info */
1880 mono_memory_barrier ();
1881 old_info->domain_vtables [domain->domain_id] = vt;
1883 int new_size = domain->domain_id;
1885 new_size = MAX (new_size, old_info->max_domain);
1887 /* make the new size a power of two */
1889 while (new_size > i)
1892 /* this is a bounded memory retention issue: may want to
1893 * handle it differently when we'll have a rcu-like system.
1895 runtime_info = mono_image_alloc0 (class->image, sizeof (MonoClassRuntimeInfo) + new_size * sizeof (gpointer));
1896 runtime_info->max_domain = new_size - 1;
1897 /* copy the stuff from the older info */
1899 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
1901 runtime_info->domain_vtables [domain->domain_id] = vt;
1903 mono_memory_barrier ();
1904 class->runtime_info = runtime_info;
1907 /* Initialize vtable */
1908 if (vtable_trampoline) {
1909 // This also covers the AOT case
1910 for (i = 0; i < class->vtable_size; ++i) {
1911 vt->vtable [i] = vtable_trampoline;
1914 mono_class_setup_vtable (class);
1916 for (i = 0; i < class->vtable_size; ++i) {
1919 if ((cm = class->vtable [i]))
1920 vt->vtable [i] = vtable_trampoline? vtable_trampoline: arch_create_jit_trampoline (cm);
1924 if (ARCH_USE_IMT && imt_table_bytes) {
1925 /* Now that the vtable is full, we can actually fill up the IMT */
1926 if (imt_trampoline) {
1927 /* lazy construction of the IMT entries enabled */
1928 for (i = 0; i < MONO_IMT_SIZE; ++i)
1929 interface_offsets [i] = imt_trampoline;
1931 build_imt (class, vt, domain, interface_offsets, NULL);
1935 mono_domain_unlock (domain);
1936 mono_loader_unlock ();
1938 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
1939 if (mono_is_security_manager_active () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND)) {
1940 MonoException *exc = mono_class_get_exception_for_failure (class);
1942 mono_raise_exception (exc);
1945 /* make sure the parent is initialized */
1947 mono_class_vtable (domain, class->parent);
1949 vt->type = mono_type_get_object (domain, &class->byval_arg);
1950 if (class->contextbound)
1959 * mono_class_proxy_vtable:
1960 * @domain: the application domain
1961 * @remove_class: the remote class
1963 * Creates a vtable for transparent proxies. It is basically
1964 * a copy of the real vtable of the class wrapped in @remote_class,
1965 * but all function pointers invoke the remoting functions, and
1966 * vtable->klass points to the transparent proxy class, and not to @class.
1969 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
1971 MonoVTable *vt, *pvt;
1972 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
1974 GSList *extra_interfaces = NULL;
1975 MonoClass *class = remote_class->proxy_class;
1976 gpointer *interface_offsets;
1978 vt = mono_class_vtable (domain, class);
1979 max_interface_id = vt->max_interface_id;
1981 /* Calculate vtable space for extra interfaces */
1982 for (j = 0; j < remote_class->interface_count; j++) {
1983 MonoClass* iclass = remote_class->interfaces[j];
1987 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
1988 continue; /* interface implemented by the class */
1989 if (g_slist_find (extra_interfaces, iclass))
1992 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
1994 method_count = mono_class_num_methods (iclass);
1996 ifaces = mono_class_get_implemented_interfaces (iclass);
1998 for (i = 0; i < ifaces->len; ++i) {
1999 MonoClass *ic = g_ptr_array_index (ifaces, i);
2000 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
2001 continue; /* interface implemented by the class */
2002 if (g_slist_find (extra_interfaces, ic))
2004 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2005 method_count += mono_class_num_methods (ic);
2007 g_ptr_array_free (ifaces, TRUE);
2010 extra_interface_vtsize += method_count * sizeof (gpointer);
2011 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2015 mono_stats.imt_number_of_tables++;
2016 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
2017 vtsize = sizeof (gpointer) * (MONO_IMT_SIZE) +
2018 sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
2020 vtsize = sizeof (gpointer) * (max_interface_id + 1) +
2021 sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
2024 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2026 interface_offsets = mono_domain_alloc0 (domain, vtsize + extra_interface_vtsize);
2028 pvt = (MonoVTable*) (interface_offsets + MONO_IMT_SIZE);
2030 pvt = (MonoVTable*) (interface_offsets + max_interface_id + 1);
2031 memcpy (pvt, vt, sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer));
2033 pvt->klass = mono_defaults.transparent_proxy_class;
2034 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2035 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2037 /* initialize vtable */
2038 mono_class_setup_vtable (class);
2039 for (i = 0; i < class->vtable_size; ++i) {
2042 if ((cm = class->vtable [i]))
2043 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2045 pvt->vtable [i] = NULL;
2048 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2049 /* create trampolines for abstract methods */
2050 for (k = class; k; k = k->parent) {
2052 gpointer iter = NULL;
2053 while ((m = mono_class_get_methods (k, &iter)))
2054 if (!pvt->vtable [m->slot])
2055 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2059 pvt->max_interface_id = max_interface_id;
2060 pvt->interface_bitmap = mono_domain_alloc0 (domain, sizeof (guint8) * (max_interface_id/8 + 1 ));
2062 if (! ARCH_USE_IMT) {
2063 /* initialize interface offsets */
2064 for (i = 0; i < class->interface_offsets_count; ++i) {
2065 int interface_id = class->interfaces_packed [i]->interface_id;
2066 int slot = class->interface_offsets_packed [i];
2067 interface_offsets [class->max_interface_id - interface_id] = &(pvt->vtable [slot]);
2070 for (i = 0; i < class->interface_offsets_count; ++i) {
2071 int interface_id = class->interfaces_packed [i]->interface_id;
2072 pvt->interface_bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2075 if (extra_interfaces) {
2076 int slot = class->vtable_size;
2082 /* Create trampolines for the methods of the interfaces */
2083 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2084 interf = list_item->data;
2086 if (! ARCH_USE_IMT) {
2087 interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
2089 pvt->interface_bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2093 while ((cm = mono_class_get_methods (interf, &iter)))
2094 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2096 slot += mono_class_num_methods (interf);
2098 if (! ARCH_USE_IMT) {
2099 g_slist_free (extra_interfaces);
2104 /* Now that the vtable is full, we can actually fill up the IMT */
2105 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
2106 if (extra_interfaces) {
2107 g_slist_free (extra_interfaces);
2115 * mono_class_field_is_special_static:
2117 * Returns whether @field is a thread/context static field.
2120 mono_class_field_is_special_static (MonoClassField *field)
2122 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2124 if (mono_field_is_deleted (field))
2126 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2127 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2134 * mono_class_has_special_static_fields:
2136 * Returns whenever @klass has any thread/context static fields.
2139 mono_class_has_special_static_fields (MonoClass *klass)
2141 MonoClassField *field;
2145 while ((field = mono_class_get_fields (klass, &iter))) {
2146 g_assert (field->parent == klass);
2147 if (mono_class_field_is_special_static (field))
2155 * create_remote_class_key:
2156 * Creates an array of pointers that can be used as a hash key for a remote class.
2157 * The first element of the array is the number of pointers.
2160 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2165 if (remote_class == NULL) {
2166 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2167 key = g_malloc (sizeof(gpointer) * 3);
2168 key [0] = GINT_TO_POINTER (2);
2169 key [1] = mono_defaults.marshalbyrefobject_class;
2170 key [2] = extra_class;
2172 key = g_malloc (sizeof(gpointer) * 2);
2173 key [0] = GINT_TO_POINTER (1);
2174 key [1] = extra_class;
2177 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2178 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2179 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2180 key [1] = remote_class->proxy_class;
2182 // Keep the list of interfaces sorted
2183 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2184 if (extra_class && remote_class->interfaces [i] > extra_class) {
2185 key [j++] = extra_class;
2188 key [j] = remote_class->interfaces [i];
2191 key [j] = extra_class;
2193 // Replace the old class. The interface list is the same
2194 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2195 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2196 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2197 for (i = 0; i < remote_class->interface_count; i++)
2198 key [2 + i] = remote_class->interfaces [i];
2206 * copy_remote_class_key:
2208 * Make a copy of KEY in the domain and return the copy.
2211 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2213 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2214 gpointer *mp_key = mono_domain_alloc (domain, key_size);
2216 memcpy (mp_key, key, key_size);
2222 * mono_remote_class:
2223 * @domain: the application domain
2224 * @class_name: name of the remote class
2226 * Creates and initializes a MonoRemoteClass object for a remote type.
2230 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2232 MonoRemoteClass *rc;
2233 gpointer* key, *mp_key;
2235 key = create_remote_class_key (NULL, proxy_class);
2237 mono_domain_lock (domain);
2238 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2242 mono_domain_unlock (domain);
2246 mp_key = copy_remote_class_key (domain, key);
2250 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2251 rc = mono_domain_alloc (domain, sizeof(MonoRemoteClass) + sizeof(MonoClass*));
2252 rc->interface_count = 1;
2253 rc->interfaces [0] = proxy_class;
2254 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2256 rc = mono_domain_alloc (domain, sizeof(MonoRemoteClass));
2257 rc->interface_count = 0;
2258 rc->proxy_class = proxy_class;
2261 rc->default_vtable = NULL;
2262 rc->xdomain_vtable = NULL;
2263 rc->proxy_class_name = mono_string_to_utf8_mp (domain->mp, class_name);
2264 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2266 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2268 mono_domain_unlock (domain);
2273 * clone_remote_class:
2274 * Creates a copy of the remote_class, adding the provided class or interface
2276 static MonoRemoteClass*
2277 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2279 MonoRemoteClass *rc;
2280 gpointer* key, *mp_key;
2282 key = create_remote_class_key (remote_class, extra_class);
2283 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2289 mp_key = copy_remote_class_key (domain, key);
2293 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2295 rc = mono_domain_alloc (domain, sizeof(MonoRemoteClass) + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2296 rc->proxy_class = remote_class->proxy_class;
2297 rc->interface_count = remote_class->interface_count + 1;
2299 // Keep the list of interfaces sorted, since the hash key of
2300 // the remote class depends on this
2301 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2302 if (remote_class->interfaces [i] > extra_class && i == j)
2303 rc->interfaces [j++] = extra_class;
2304 rc->interfaces [j] = remote_class->interfaces [i];
2307 rc->interfaces [j] = extra_class;
2309 // Replace the old class. The interface array is the same
2310 rc = mono_domain_alloc (domain, sizeof(MonoRemoteClass) + sizeof(MonoClass*) * remote_class->interface_count);
2311 rc->proxy_class = extra_class;
2312 rc->interface_count = remote_class->interface_count;
2313 if (rc->interface_count > 0)
2314 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2317 rc->default_vtable = NULL;
2318 rc->xdomain_vtable = NULL;
2319 rc->proxy_class_name = remote_class->proxy_class_name;
2321 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2327 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2329 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2330 mono_domain_lock (domain);
2331 if (rp->target_domain_id != -1) {
2332 if (remote_class->xdomain_vtable == NULL)
2333 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2334 mono_domain_unlock (domain);
2335 mono_loader_unlock ();
2336 return remote_class->xdomain_vtable;
2338 if (remote_class->default_vtable == NULL) {
2341 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2342 klass = mono_class_from_mono_type (type);
2343 if ((klass->is_com_object || (mono_defaults.com_object_class && klass == mono_defaults.com_object_class)) && !mono_class_vtable (mono_domain_get (), klass)->remote)
2344 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2346 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2349 mono_domain_unlock (domain);
2350 mono_loader_unlock ();
2351 return remote_class->default_vtable;
2355 * mono_upgrade_remote_class:
2356 * @domain: the application domain
2357 * @tproxy: the proxy whose remote class has to be upgraded.
2358 * @klass: class to which the remote class can be casted.
2360 * Updates the vtable of the remote class by adding the necessary method slots
2361 * and interface offsets so it can be safely casted to klass. klass can be a
2362 * class or an interface.
2365 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2367 MonoTransparentProxy *tproxy;
2368 MonoRemoteClass *remote_class;
2369 gboolean redo_vtable;
2371 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2372 mono_domain_lock (domain);
2374 tproxy = (MonoTransparentProxy*) proxy_object;
2375 remote_class = tproxy->remote_class;
2377 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2380 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2381 if (remote_class->interfaces [i] == klass)
2382 redo_vtable = FALSE;
2385 redo_vtable = (remote_class->proxy_class != klass);
2389 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2390 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2393 mono_domain_unlock (domain);
2394 mono_loader_unlock ();
2399 * mono_object_get_virtual_method:
2400 * @obj: object to operate on.
2403 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2404 * the instance of a callvirt of method.
2407 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2410 MonoMethod **vtable;
2412 MonoMethod *res = NULL;
2414 klass = mono_object_class (obj);
2415 if (klass == mono_defaults.transparent_proxy_class) {
2416 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2422 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2425 mono_class_setup_vtable (klass);
2426 vtable = klass->vtable;
2428 if (method->slot == -1) {
2429 /* method->slot might not be set for instances of generic methods */
2430 if (method->is_inflated) {
2431 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2432 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2435 g_assert_not_reached ();
2439 /* check method->slot is a valid index: perform isinstance? */
2440 if (method->slot != -1) {
2441 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2443 res = vtable [mono_class_interface_offset (klass, method->klass) + method->slot];
2445 res = vtable [method->slot];
2450 /* It may be an interface, abstract class method or generic method */
2451 if (!res || mono_method_signature (res)->generic_param_count)
2454 /* generic methods demand invoke_with_check */
2455 if (mono_method_signature (res)->generic_param_count)
2456 res = mono_marshal_get_remoting_invoke_with_check (res);
2458 res = mono_marshal_get_remoting_invoke (res);
2460 if (method->is_inflated) {
2461 /* Have to inflate the result */
2462 res = mono_class_inflate_generic_method (res, &((MonoMethodInflated*)method)->context);
2472 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2474 g_error ("runtime invoke called on uninitialized runtime");
2478 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2481 * mono_runtime_invoke:
2482 * @method: method to invoke
2483 * @obJ: object instance
2484 * @params: arguments to the method
2485 * @exc: exception information.
2487 * Invokes the method represented by @method on the object @obj.
2489 * obj is the 'this' pointer, it should be NULL for static
2490 * methods, a MonoObject* for object instances and a pointer to
2491 * the value type for value types.
2493 * The params array contains the arguments to the method with the
2494 * same convention: MonoObject* pointers for object instances and
2495 * pointers to the value type otherwise.
2497 * From unmanaged code you'll usually use the
2498 * mono_runtime_invoke() variant.
2500 * Note that this function doesn't handle virtual methods for
2501 * you, it will exec the exact method you pass: we still need to
2502 * expose a function to lookup the derived class implementation
2503 * of a virtual method (there are examples of this in the code,
2506 * You can pass NULL as the exc argument if you don't want to
2507 * catch exceptions, otherwise, *exc will be set to the exception
2508 * thrown, if any. if an exception is thrown, you can't use the
2509 * MonoObject* result from the function.
2511 * If the method returns a value type, it is boxed in an object
2515 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2517 if (mono_runtime_get_no_exec ())
2518 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2520 return default_mono_runtime_invoke (method, obj, params, exc);
2524 * mono_method_get_unmanaged_thunk:
2525 * @method: method to generate a thunk for.
2527 * Returns an unmanaged->managed thunk that can be used to call
2528 * a managed method directly from C.
2530 * The thunk's C signature closely matches the managed signature:
2532 * C#: public bool Equals (object obj);
2533 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2534 * MonoObject*, MonoException**);
2536 * The 1st ("this") parameter must not be used with static methods:
2538 * C#: public static bool ReferenceEquals (object a, object b);
2539 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2542 * The last argument must be a non-null pointer of a MonoException* pointer.
2543 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2544 * exception has been thrown in managed code. Otherwise it will point
2545 * to the MonoException* caught by the thunk. In this case, the result of
2546 * the thunk is undefined:
2548 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2549 * MonoException *ex = NULL;
2550 * Equals func = mono_method_get_unmanaged_thunk (method);
2551 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2553 * // handle exception
2556 * The calling convention of the thunk matches the platform's default
2557 * convention. This means that under Windows, C declarations must
2558 * contain the __stdcall attribute:
2560 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2561 * MonoObject*, MonoException**);
2565 * Value type arguments and return values are treated as they were objects:
2567 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2568 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2570 * Arguments must be properly boxed upon trunk's invocation, while return
2571 * values must be unboxed.
2574 mono_method_get_unmanaged_thunk (MonoMethod *method)
2576 method = mono_marshal_get_thunk_invoke_wrapper (method);
2577 return mono_compile_method (method);
2581 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
2585 gpointer *p = (gpointer*)dest;
2592 case MONO_TYPE_BOOLEAN:
2594 case MONO_TYPE_U1: {
2595 guint8 *p = (guint8*)dest;
2596 *p = value ? *(guint8*)value : 0;
2601 case MONO_TYPE_CHAR: {
2602 guint16 *p = (guint16*)dest;
2603 *p = value ? *(guint16*)value : 0;
2606 #if SIZEOF_VOID_P == 4
2611 case MONO_TYPE_U4: {
2612 gint32 *p = (gint32*)dest;
2613 *p = value ? *(gint32*)value : 0;
2616 #if SIZEOF_VOID_P == 8
2621 case MONO_TYPE_U8: {
2622 gint64 *p = (gint64*)dest;
2623 *p = value ? *(gint64*)value : 0;
2626 case MONO_TYPE_R4: {
2627 float *p = (float*)dest;
2628 *p = value ? *(float*)value : 0;
2631 case MONO_TYPE_R8: {
2632 double *p = (double*)dest;
2633 *p = value ? *(double*)value : 0;
2636 case MONO_TYPE_STRING:
2637 case MONO_TYPE_SZARRAY:
2638 case MONO_TYPE_CLASS:
2639 case MONO_TYPE_OBJECT:
2640 case MONO_TYPE_ARRAY:
2641 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2643 case MONO_TYPE_FNPTR:
2644 case MONO_TYPE_PTR: {
2645 gpointer *p = (gpointer*)dest;
2646 *p = deref_pointer? *(gpointer*)value: value;
2649 case MONO_TYPE_VALUETYPE:
2650 /* note that 't' and 'type->type' can be different */
2651 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
2652 t = mono_class_enum_basetype (type->data.klass)->type;
2656 size = mono_class_value_size (mono_class_from_mono_type (type), NULL);
2658 memset (dest, 0, size);
2660 memcpy (dest, value, size);
2663 case MONO_TYPE_GENERICINST:
2664 t = type->data.generic_class->container_class->byval_arg.type;
2667 g_warning ("got type %x", type->type);
2668 g_assert_not_reached ();
2673 * mono_field_set_value:
2674 * @obj: Instance object
2675 * @field: MonoClassField describing the field to set
2676 * @value: The value to be set
2678 * Sets the value of the field described by @field in the object instance @obj
2679 * to the value passed in @value. This method should only be used for instance
2680 * fields. For static fields, use mono_field_static_set_value.
2682 * The value must be on the native format of the field type.
2685 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
2689 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2691 dest = (char*)obj + field->offset;
2692 set_value (field->type, dest, value, FALSE);
2696 * mono_field_static_set_value:
2697 * @field: MonoClassField describing the field to set
2698 * @value: The value to be set
2700 * Sets the value of the static field described by @field
2701 * to the value passed in @value.
2703 * The value must be on the native format of the field type.
2706 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
2710 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2711 /* you cant set a constant! */
2712 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
2714 if (field->offset == -1) {
2715 /* Special static */
2716 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
2717 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
2719 dest = (char*)vt->data + field->offset;
2721 set_value (field->type, dest, value, FALSE);
2724 /* Used by the debugger */
2726 mono_vtable_get_static_field_data (MonoVTable *vt)
2732 * mono_field_get_value:
2733 * @obj: Object instance
2734 * @field: MonoClassField describing the field to fetch information from
2735 * @value: pointer to the location where the value will be stored
2737 * Use this routine to get the value of the field @field in the object
2740 * The pointer provided by value must be of the field type, for reference
2741 * types this is a MonoObject*, for value types its the actual pointer to
2746 * mono_field_get_value (obj, int_field, &i);
2749 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
2753 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2755 src = (char*)obj + field->offset;
2756 set_value (field->type, value, src, TRUE);
2760 * mono_field_get_value_object:
2761 * @domain: domain where the object will be created (if boxing)
2762 * @field: MonoClassField describing the field to fetch information from
2763 * @obj: The object instance for the field.
2765 * Returns: a new MonoObject with the value from the given field. If the
2766 * field represents a value type, the value is boxed.
2770 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
2774 MonoVTable *vtable = NULL;
2776 gboolean is_static = FALSE;
2777 gboolean is_ref = FALSE;
2779 switch (field->type->type) {
2780 case MONO_TYPE_STRING:
2781 case MONO_TYPE_OBJECT:
2782 case MONO_TYPE_CLASS:
2783 case MONO_TYPE_ARRAY:
2784 case MONO_TYPE_SZARRAY:
2789 case MONO_TYPE_BOOLEAN:
2792 case MONO_TYPE_CHAR:
2801 case MONO_TYPE_VALUETYPE:
2802 is_ref = field->type->byref;
2804 case MONO_TYPE_GENERICINST:
2805 is_ref = !field->type->data.generic_class->container_class->valuetype;
2808 g_error ("type 0x%x not handled in "
2809 "mono_field_get_value_object", field->type->type);
2813 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
2815 vtable = mono_class_vtable (domain, field->parent);
2816 if (!vtable->initialized)
2817 mono_runtime_class_init (vtable);
2822 mono_field_static_get_value (vtable, field, &o);
2824 mono_field_get_value (obj, field, &o);
2829 /* boxed value type */
2830 klass = mono_class_from_mono_type (field->type);
2831 o = mono_object_new (domain, klass);
2832 v = ((gchar *) o) + sizeof (MonoObject);
2834 mono_field_static_get_value (vtable, field, v);
2836 mono_field_get_value (obj, field, v);
2843 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
2846 const char *p = blob;
2847 mono_metadata_decode_blob_size (p, &p);
2850 case MONO_TYPE_BOOLEAN:
2853 *(guint8 *) value = *p;
2855 case MONO_TYPE_CHAR:
2858 *(guint16*) value = read16 (p);
2862 *(guint32*) value = read32 (p);
2866 *(guint64*) value = read64 (p);
2869 readr4 (p, (float*) value);
2872 readr8 (p, (double*) value);
2874 case MONO_TYPE_STRING:
2875 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
2877 case MONO_TYPE_CLASS:
2878 *(gpointer*) value = NULL;
2882 g_warning ("type 0x%02x should not be in constant table", type);
2888 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
2890 MonoTypeEnum def_type;
2893 data = mono_class_get_field_default_value (field, &def_type);
2894 mono_get_constant_value_from_blob (domain, def_type, data, value);
2898 * mono_field_static_get_value:
2899 * @vt: vtable to the object
2900 * @field: MonoClassField describing the field to fetch information from
2901 * @value: where the value is returned
2903 * Use this routine to get the value of the static field @field value.
2905 * The pointer provided by value must be of the field type, for reference
2906 * types this is a MonoObject*, for value types its the actual pointer to
2911 * mono_field_static_get_value (vt, int_field, &i);
2914 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
2918 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2920 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
2921 get_default_field_value (vt->domain, field, value);
2925 if (field->offset == -1) {
2926 /* Special static */
2927 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
2928 src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
2930 src = (char*)vt->data + field->offset;
2932 set_value (field->type, value, src, TRUE);
2936 * mono_property_set_value:
2937 * @prop: MonoProperty to set
2938 * @obj: instance object on which to act
2939 * @params: parameters to pass to the propery
2940 * @exc: optional exception
2942 * Invokes the property's set method with the given arguments on the
2943 * object instance obj (or NULL for static properties).
2945 * You can pass NULL as the exc argument if you don't want to
2946 * catch exceptions, otherwise, *exc will be set to the exception
2947 * thrown, if any. if an exception is thrown, you can't use the
2948 * MonoObject* result from the function.
2951 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
2953 default_mono_runtime_invoke (prop->set, obj, params, exc);
2957 * mono_property_get_value:
2958 * @prop: MonoProperty to fetch
2959 * @obj: instance object on which to act
2960 * @params: parameters to pass to the propery
2961 * @exc: optional exception
2963 * Invokes the property's get method with the given arguments on the
2964 * object instance obj (or NULL for static properties).
2966 * You can pass NULL as the exc argument if you don't want to
2967 * catch exceptions, otherwise, *exc will be set to the exception
2968 * thrown, if any. if an exception is thrown, you can't use the
2969 * MonoObject* result from the function.
2971 * Returns: the value from invoking the get method on the property.
2974 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
2976 return default_mono_runtime_invoke (prop->get, obj, params, exc);
2980 * mono_nullable_init:
2981 * @buf: The nullable structure to initialize.
2982 * @value: the value to initialize from
2983 * @klass: the type for the object
2985 * Initialize the nullable structure pointed to by @buf from @value which
2986 * should be a boxed value type. The size of @buf should be able to hold
2987 * as much data as the @klass->instance_size (which is the number of bytes
2988 * that will be copies).
2990 * Since Nullables have variable structure, we can not define a C
2991 * structure for them.
2994 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
2996 MonoClass *param_class = klass->cast_class;
2998 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
2999 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3001 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3003 memcpy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3005 memset (buf + klass->fields [0].offset - sizeof (MonoObject), 0, mono_class_value_size (param_class, NULL));
3009 * mono_nullable_box:
3010 * @buf: The buffer representing the data to be boxed
3011 * @klass: the type to box it as.
3013 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3017 mono_nullable_box (guint8 *buf, MonoClass *klass)
3019 MonoClass *param_class = klass->cast_class;
3021 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3022 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3024 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3025 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
3026 memcpy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3034 * mono_get_delegate_invoke:
3035 * @klass: The delegate class
3037 * Returns: the MonoMethod for the "Invoke" method in the delegate klass
3040 mono_get_delegate_invoke (MonoClass *klass)
3044 /* This is called at runtime, so avoid the slower search in metadata */
3045 mono_class_setup_methods (klass);
3047 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3054 * mono_runtime_delegate_invoke:
3055 * @delegate: pointer to a delegate object.
3056 * @params: parameters for the delegate.
3057 * @exc: Pointer to the exception result.
3059 * Invokes the delegate method @delegate with the parameters provided.
3061 * You can pass NULL as the exc argument if you don't want to
3062 * catch exceptions, otherwise, *exc will be set to the exception
3063 * thrown, if any. if an exception is thrown, you can't use the
3064 * MonoObject* result from the function.
3067 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3071 im = mono_get_delegate_invoke (delegate->vtable->klass);
3074 return mono_runtime_invoke (im, delegate, params, exc);
3077 static char **main_args = NULL;
3078 static int num_main_args;
3081 * mono_runtime_get_main_args:
3083 * Returns: a MonoArray with the arguments passed to the main program
3086 mono_runtime_get_main_args (void)
3090 MonoDomain *domain = mono_domain_get ();
3095 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3097 for (i = 0; i < num_main_args; ++i)
3098 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3104 fire_process_exit_event (void)
3106 MonoClassField *field;
3107 MonoDomain *domain = mono_domain_get ();
3109 MonoObject *delegate, *exc;
3111 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "ProcessExit");
3114 if (domain != mono_get_root_domain ())
3117 delegate = *(MonoObject **)(((char *)domain->domain) + field->offset);
3118 if (delegate == NULL)
3123 mono_runtime_delegate_invoke (delegate, pa, &exc);
3127 * mono_runtime_run_main:
3128 * @method: the method to start the application with (usually Main)
3129 * @argc: number of arguments from the command line
3130 * @argv: array of strings from the command line
3131 * @exc: excetption results
3133 * Execute a standard Main() method (argc/argv contains the
3134 * executable name). This method also sets the command line argument value
3135 * needed by System.Environment.
3140 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3144 MonoArray *args = NULL;
3145 MonoDomain *domain = mono_domain_get ();
3146 gchar *utf8_fullpath;
3149 g_assert (method != NULL);
3151 mono_thread_set_main (mono_thread_current ());
3153 main_args = g_new0 (char*, argc);
3154 num_main_args = argc;
3156 if (!g_path_is_absolute (argv [0])) {
3157 gchar *basename = g_path_get_basename (argv [0]);
3158 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3162 utf8_fullpath = mono_utf8_from_external (fullpath);
3163 if(utf8_fullpath == NULL) {
3164 /* Printing the arg text will cause glib to
3165 * whinge about "Invalid UTF-8", but at least
3166 * its relevant, and shows the problem text
3169 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3170 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3177 utf8_fullpath = mono_utf8_from_external (argv[0]);
3178 if(utf8_fullpath == NULL) {
3179 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3180 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3185 main_args [0] = utf8_fullpath;
3187 for (i = 1; i < argc; ++i) {
3190 utf8_arg=mono_utf8_from_external (argv[i]);
3191 if(utf8_arg==NULL) {
3192 /* Ditto the comment about Invalid UTF-8 here */
3193 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3194 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3198 main_args [i] = utf8_arg;
3202 if (mono_method_signature (method)->param_count) {
3203 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3204 for (i = 0; i < argc; ++i) {
3205 /* The encodings should all work, given that
3206 * we've checked all these args for the
3209 gchar *str = mono_utf8_from_external (argv [i]);
3210 MonoString *arg = mono_string_new (domain, str);
3211 mono_array_setref (args, i, arg);
3215 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3218 mono_assembly_set_main (method->klass->image->assembly);
3220 result = mono_runtime_exec_main (method, args, exc);
3221 fire_process_exit_event ();
3225 /* Used in call_unhandled_exception_delegate */
3227 create_unhandled_exception_eventargs (MonoObject *exc)
3231 MonoMethod *method = NULL;
3232 MonoBoolean is_terminating = TRUE;
3235 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
3238 mono_class_init (klass);
3240 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
3241 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
3245 args [1] = &is_terminating;
3247 obj = mono_object_new (mono_domain_get (), klass);
3248 mono_runtime_invoke (method, obj, args, NULL);
3253 /* Used in mono_unhandled_exception */
3255 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
3256 MonoObject *e = NULL;
3259 pa [0] = domain->domain;
3260 pa [1] = create_unhandled_exception_eventargs (exc);
3261 mono_runtime_delegate_invoke (delegate, pa, &e);
3264 gchar *msg = mono_string_to_utf8 (((MonoException *) e)->message);
3265 g_warning ("exception inside UnhandledException handler: %s\n", msg);
3270 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
3273 * mono_runtime_unhandled_exception_policy_set:
3274 * @policy: the new policy
3276 * This is a VM internal routine.
3278 * Sets the runtime policy for handling unhandled exceptions.
3281 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
3282 runtime_unhandled_exception_policy = policy;
3286 * mono_runtime_unhandled_exception_policy_get:
3288 * This is a VM internal routine.
3290 * Gets the runtime policy for handling unhandled exceptions.
3292 MonoRuntimeUnhandledExceptionPolicy
3293 mono_runtime_unhandled_exception_policy_get (void) {
3294 return runtime_unhandled_exception_policy;
3298 * mono_unhandled_exception:
3299 * @exc: exception thrown
3301 * This is a VM internal routine.
3303 * We call this function when we detect an unhandled exception
3304 * in the default domain.
3306 * It invokes the * UnhandledException event in AppDomain or prints
3307 * a warning to the console
3310 mono_unhandled_exception (MonoObject *exc)
3312 MonoDomain *current_domain = mono_domain_get ();
3313 MonoDomain *root_domain = mono_get_root_domain ();
3314 MonoClassField *field;
3315 MonoObject *current_appdomain_delegate;
3316 MonoObject *root_appdomain_delegate;
3318 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
3319 "UnhandledException");
3322 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
3323 gboolean abort_process = (mono_thread_current () == main_thread) ||
3324 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT);
3325 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
3326 if (current_domain != root_domain && (mono_framework_version () >= 2)) {
3327 current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
3329 current_appdomain_delegate = NULL;
3332 /* set exitcode only if we will abort the process */
3334 mono_environment_exitcode_set (1);
3335 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
3336 mono_print_unhandled_exception (exc);
3338 if (root_appdomain_delegate) {
3339 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
3341 if (current_appdomain_delegate) {
3342 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
3349 * Launch a new thread to execute a function
3351 * main_func is called back from the thread with main_args as the
3352 * parameter. The callback function is expected to start Main()
3353 * eventually. This function then waits for all managed threads to
3355 * It is not necesseray anymore to execute managed code in a subthread,
3356 * so this function should not be used anymore by default: just
3357 * execute the code and then call mono_thread_manage ().
3360 mono_runtime_exec_managed_code (MonoDomain *domain,
3361 MonoMainThreadFunc main_func,
3364 mono_thread_create (domain, main_func, main_args);
3366 mono_thread_manage ();
3370 * Execute a standard Main() method (args doesn't contain the
3374 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
3379 MonoCustomAttrInfo* cinfo;
3380 gboolean has_stathread_attribute;
3381 MonoThread* thread = mono_thread_current ();
3387 domain = mono_object_domain (args);
3388 if (!domain->entry_assembly) {
3390 MonoAssembly *assembly;
3392 assembly = method->klass->image->assembly;
3393 domain->entry_assembly = assembly;
3394 /* Domains created from another domain already have application_base and configuration_file set */
3395 if (domain->setup->application_base == NULL) {
3396 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
3399 if (domain->setup->configuration_file == NULL) {
3400 str = g_strconcat (assembly->image->name, ".config", NULL);
3401 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
3403 mono_set_private_bin_path_from_config (domain);
3407 cinfo = mono_custom_attrs_from_method (method);
3409 static MonoClass *stathread_attribute = NULL;
3410 if (!stathread_attribute)
3411 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
3412 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
3414 mono_custom_attrs_free (cinfo);
3416 has_stathread_attribute = FALSE;
3418 if (has_stathread_attribute) {
3419 thread->apartment_state = ThreadApartmentState_STA;
3420 } else if (mono_framework_version () == 1) {
3421 thread->apartment_state = ThreadApartmentState_Unknown;
3423 thread->apartment_state = ThreadApartmentState_MTA;
3425 mono_thread_init_apartment_state ();
3427 mono_debugger_event (MONO_DEBUGGER_EVENT_REACHED_MAIN, 0, 0);
3429 /* FIXME: check signature of method */
3430 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
3432 res = mono_runtime_invoke (method, NULL, pa, exc);
3434 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
3438 mono_environment_exitcode_set (rval);
3440 mono_runtime_invoke (method, NULL, pa, exc);
3444 /* If the return type of Main is void, only
3445 * set the exitcode if an exception was thrown
3446 * (we don't want to blow away an
3447 * explicitly-set exit code)
3450 mono_environment_exitcode_set (rval);
3454 mono_debugger_event (MONO_DEBUGGER_EVENT_MAIN_EXITED, (guint64) (gsize) rval, 0);
3460 * mono_install_runtime_invoke:
3461 * @func: Function to install
3463 * This is a VM internal routine
3466 mono_install_runtime_invoke (MonoInvokeFunc func)
3468 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
3473 * mono_runtime_invoke_array:
3474 * @method: method to invoke
3475 * @obJ: object instance
3476 * @params: arguments to the method
3477 * @exc: exception information.
3479 * Invokes the method represented by @method on the object @obj.
3481 * obj is the 'this' pointer, it should be NULL for static
3482 * methods, a MonoObject* for object instances and a pointer to
3483 * the value type for value types.
3485 * The params array contains the arguments to the method with the
3486 * same convention: MonoObject* pointers for object instances and
3487 * pointers to the value type otherwise. The _invoke_array
3488 * variant takes a C# object[] as the params argument (MonoArray
3489 * *params): in this case the value types are boxed inside the
3490 * respective reference representation.
3492 * From unmanaged code you'll usually use the
3493 * mono_runtime_invoke() variant.
3495 * Note that this function doesn't handle virtual methods for
3496 * you, it will exec the exact method you pass: we still need to
3497 * expose a function to lookup the derived class implementation
3498 * of a virtual method (there are examples of this in the code,
3501 * You can pass NULL as the exc argument if you don't want to
3502 * catch exceptions, otherwise, *exc will be set to the exception
3503 * thrown, if any. if an exception is thrown, you can't use the
3504 * MonoObject* result from the function.
3506 * If the method returns a value type, it is boxed in an object
3510 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
3513 MonoMethodSignature *sig = mono_method_signature (method);
3514 gpointer *pa = NULL;
3517 gboolean has_byref_nullables = FALSE;
3519 if (NULL != params) {
3520 pa = alloca (sizeof (gpointer) * mono_array_length (params));
3521 for (i = 0; i < mono_array_length (params); i++) {
3522 MonoType *t = sig->params [i];
3528 case MONO_TYPE_BOOLEAN:
3531 case MONO_TYPE_CHAR:
3540 case MONO_TYPE_VALUETYPE:
3541 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
3542 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
3543 pa [i] = mono_array_get (params, MonoObject*, i);
3545 has_byref_nullables = TRUE;
3547 /* MS seems to create the objects if a null is passed in */
3548 if (!mono_array_get (params, MonoObject*, i))
3549 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
3553 * We can't pass the unboxed vtype byref to the callee, since
3554 * that would mean the callee would be able to modify boxed
3555 * primitive types. So we (and MS) make a copy of the boxed
3556 * object, pass that to the callee, and replace the original
3557 * boxed object in the arg array with the copy.
3559 MonoObject *orig = mono_array_get (params, MonoObject*, i);
3560 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
3561 mono_array_setref (params, i, copy);
3564 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
3567 case MONO_TYPE_STRING:
3568 case MONO_TYPE_OBJECT:
3569 case MONO_TYPE_CLASS:
3570 case MONO_TYPE_ARRAY:
3571 case MONO_TYPE_SZARRAY:
3573 pa [i] = mono_array_addr (params, MonoObject*, i);
3574 // FIXME: I need to check this code path
3576 pa [i] = mono_array_get (params, MonoObject*, i);
3578 case MONO_TYPE_GENERICINST:
3580 t = &t->data.generic_class->container_class->this_arg;
3582 t = &t->data.generic_class->container_class->byval_arg;
3585 g_error ("type 0x%x not handled in ves_icall_InternalInvoke", sig->params [i]->type);
3590 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
3593 if (mono_class_is_nullable (method->klass)) {
3594 /* Need to create a boxed vtype instead */
3600 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
3604 obj = mono_object_new (mono_domain_get (), method->klass);
3605 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
3606 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
3608 if (method->klass->valuetype)
3609 o = mono_object_unbox (obj);
3612 } else if (method->klass->valuetype) {
3613 obj = mono_value_box (mono_domain_get (), method->klass, obj);
3616 mono_runtime_invoke (method, o, pa, exc);
3619 if (mono_class_is_nullable (method->klass)) {
3620 MonoObject *nullable;
3622 /* Convert the unboxed vtype into a Nullable structure */
3623 nullable = mono_object_new (mono_domain_get (), method->klass);
3625 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
3626 obj = mono_object_unbox (nullable);
3629 /* obj must be already unboxed if needed */
3630 res = mono_runtime_invoke (method, obj, pa, exc);
3632 if (has_byref_nullables) {
3634 * The runtime invoke wrapper already converted byref nullables back,
3635 * and stored them in pa, we just need to copy them back to the
3638 for (i = 0; i < mono_array_length (params); i++) {
3639 MonoType *t = sig->params [i];
3641 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
3642 mono_array_setref (params, i, pa [i]);
3651 arith_overflow (void)
3653 mono_raise_exception (mono_get_exception_overflow ());
3657 * mono_object_allocate:
3658 * @size: number of bytes to allocate
3660 * This is a very simplistic routine until we have our GC-aware
3663 * Returns: an allocated object of size @size, or NULL on failure.
3665 static inline void *
3666 mono_object_allocate (size_t size, MonoVTable *vtable)
3669 mono_stats.new_object_count++;
3670 ALLOC_OBJECT (o, vtable, size);
3676 * mono_object_allocate_ptrfree:
3677 * @size: number of bytes to allocate
3679 * Note that the memory allocated is not zeroed.
3680 * Returns: an allocated object of size @size, or NULL on failure.
3682 static inline void *
3683 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
3686 mono_stats.new_object_count++;
3687 ALLOC_PTRFREE (o, vtable, size);
3691 static inline void *
3692 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
3695 ALLOC_TYPED (o, size, vtable);
3696 mono_stats.new_object_count++;
3703 * @klass: the class of the object that we want to create
3705 * Returns: a newly created object whose definition is
3706 * looked up using @klass. This will not invoke any constructors,
3707 * so the consumer of this routine has to invoke any constructors on
3708 * its own to initialize the object.
3711 mono_object_new (MonoDomain *domain, MonoClass *klass)
3713 MONO_ARCH_SAVE_REGS;
3714 return mono_object_new_specific (mono_class_vtable (domain, klass));
3718 * mono_object_new_specific:
3719 * @vtable: the vtable of the object that we want to create
3721 * Returns: A newly created object with class and domain specified
3725 mono_object_new_specific (MonoVTable *vtable)
3729 MONO_ARCH_SAVE_REGS;
3731 /* check for is_com_object for COM Interop */
3732 if (vtable->remote || vtable->klass->is_com_object)
3735 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
3738 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
3741 mono_class_init (klass);
3743 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
3745 vtable->domain->create_proxy_for_type_method = im;
3748 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
3750 o = mono_runtime_invoke (im, NULL, pa, NULL);
3751 if (o != NULL) return o;
3754 return mono_object_new_alloc_specific (vtable);
3758 mono_object_new_alloc_specific (MonoVTable *vtable)
3762 if (!vtable->klass->has_references) {
3763 o = mono_object_new_ptrfree (vtable);
3764 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3765 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
3767 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
3768 o = mono_object_allocate (vtable->klass->instance_size, vtable);
3770 if (G_UNLIKELY (vtable->klass->has_finalize))
3771 mono_object_register_finalizer (o);
3773 if (G_UNLIKELY (profile_allocs))
3774 mono_profiler_allocation (o, vtable->klass);
3779 mono_object_new_fast (MonoVTable *vtable)
3782 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
3787 mono_object_new_ptrfree (MonoVTable *vtable)
3790 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
3791 #if NEED_TO_ZERO_PTRFREE
3792 /* an inline memset is much faster for the common vcase of small objects
3793 * note we assume the allocated size is a multiple of sizeof (void*).
3795 if (vtable->klass->instance_size < 128) {
3797 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
3798 p = (gpointer*)((char*)obj + sizeof (MonoObject));
3804 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
3811 mono_object_new_ptrfree_box (MonoVTable *vtable)
3814 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
3815 /* the object will be boxed right away, no need to memzero it */
3820 * mono_class_get_allocation_ftn:
3822 * @for_box: the object will be used for boxing
3823 * @pass_size_in_words:
3825 * Return the allocation function appropriate for the given class.
3829 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
3831 *pass_size_in_words = FALSE;
3833 if (!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
3834 profile_allocs = FALSE;
3836 if (vtable->klass->has_finalize || vtable->klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
3837 return mono_object_new_specific;
3839 if (!vtable->klass->has_references) {
3840 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
3842 return mono_object_new_ptrfree_box;
3843 return mono_object_new_ptrfree;
3846 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3848 return mono_object_new_fast;
3851 * FIXME: This is actually slower than mono_object_new_fast, because
3852 * of the overhead of parameter passing.
3855 *pass_size_in_words = TRUE;
3856 #ifdef GC_REDIRECT_TO_LOCAL
3857 return GC_local_gcj_fast_malloc;
3859 return GC_gcj_fast_malloc;
3864 return mono_object_new_specific;
3868 * mono_object_new_from_token:
3869 * @image: Context where the type_token is hosted
3870 * @token: a token of the type that we want to create
3872 * Returns: A newly created object whose definition is
3873 * looked up using @token in the @image image
3876 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
3880 class = mono_class_get (image, token);
3882 return mono_object_new (domain, class);
3887 * mono_object_clone:
3888 * @obj: the object to clone
3890 * Returns: A newly created object who is a shallow copy of @obj
3893 mono_object_clone (MonoObject *obj)
3898 size = obj->vtable->klass->instance_size;
3899 o = mono_object_allocate (size, obj->vtable);
3900 /* do not copy the sync state */
3901 memcpy ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
3904 if (obj->vtable->klass->has_references)
3905 mono_gc_wbarrier_object (o);
3907 if (G_UNLIKELY (profile_allocs))
3908 mono_profiler_allocation (o, obj->vtable->klass);
3910 if (obj->vtable->klass->has_finalize)
3911 mono_object_register_finalizer (o);
3916 * mono_array_full_copy:
3917 * @src: source array to copy
3918 * @dest: destination array
3920 * Copies the content of one array to another with exactly the same type and size.
3923 mono_array_full_copy (MonoArray *src, MonoArray *dest)
3925 mono_array_size_t size;
3926 MonoClass *klass = src->obj.vtable->klass;
3928 MONO_ARCH_SAVE_REGS;
3930 g_assert (klass == dest->obj.vtable->klass);
3932 size = mono_array_length (src);
3933 g_assert (size == mono_array_length (dest));
3934 size *= mono_array_element_size (klass);
3936 if (klass->element_class->valuetype) {
3937 if (klass->element_class->has_references)
3938 mono_value_copy_array (dest, 0, mono_array_addr_with_size (src, 0, 0), mono_array_length (src));
3940 memcpy (&dest->vector, &src->vector, size);
3942 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
3945 memcpy (&dest->vector, &src->vector, size);
3950 * mono_array_clone_in_domain:
3951 * @domain: the domain in which the array will be cloned into
3952 * @array: the array to clone
3954 * This routine returns a copy of the array that is hosted on the
3955 * specified MonoDomain.
3958 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
3961 mono_array_size_t size, i;
3962 mono_array_size_t *sizes;
3963 MonoClass *klass = array->obj.vtable->klass;
3965 MONO_ARCH_SAVE_REGS;
3967 if (array->bounds == NULL) {
3968 size = mono_array_length (array);
3969 o = mono_array_new_full (domain, klass, &size, NULL);
3971 size *= mono_array_element_size (klass);
3973 if (klass->element_class->valuetype) {
3974 if (klass->element_class->has_references)
3975 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
3977 memcpy (&o->vector, &array->vector, size);
3979 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
3982 memcpy (&o->vector, &array->vector, size);
3987 sizes = alloca (klass->rank * sizeof(mono_array_size_t) * 2);
3988 size = mono_array_element_size (klass);
3989 for (i = 0; i < klass->rank; ++i) {
3990 sizes [i] = array->bounds [i].length;
3991 size *= array->bounds [i].length;
3992 sizes [i + klass->rank] = array->bounds [i].lower_bound;
3994 o = mono_array_new_full (domain, klass, sizes, sizes + klass->rank);
3996 if (klass->element_class->valuetype) {
3997 if (klass->element_class->has_references)
3998 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4000 memcpy (&o->vector, &array->vector, size);
4002 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4005 memcpy (&o->vector, &array->vector, size);
4013 * @array: the array to clone
4015 * Returns: A newly created array who is a shallow copy of @array
4018 mono_array_clone (MonoArray *array)
4020 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
4023 /* helper macros to check for overflow when calculating the size of arrays */
4024 #ifdef MONO_BIG_ARRAYS
4025 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
4026 #define MYGUINT_MAX MYGUINT64_MAX
4027 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4028 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
4029 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4030 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
4031 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
4033 #define MYGUINT32_MAX 4294967295U
4034 #define MYGUINT_MAX MYGUINT32_MAX
4035 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4036 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
4037 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4038 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
4039 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
4043 * mono_array_new_full:
4044 * @domain: domain where the object is created
4045 * @array_class: array class
4046 * @lengths: lengths for each dimension in the array
4047 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
4049 * This routine creates a new array objects with the given dimensions,
4050 * lower bounds and type.
4053 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, mono_array_size_t *lengths, mono_array_size_t *lower_bounds)
4055 mono_array_size_t byte_len, len, bounds_size;
4061 if (!array_class->inited)
4062 mono_class_init (array_class);
4064 byte_len = mono_array_element_size (array_class);
4067 /* A single dimensional array with a 0 lower bound is the same as an szarray */
4068 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
4070 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
4074 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
4076 for (i = 0; i < array_class->rank; ++i) {
4077 if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
4079 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
4080 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4085 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
4086 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4088 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
4089 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4090 byte_len += sizeof (MonoArray);
4093 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
4094 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4095 byte_len = (byte_len + 3) & ~3;
4096 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
4097 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4098 byte_len += bounds_size;
4101 * Following three lines almost taken from mono_object_new ():
4102 * they need to be kept in sync.
4104 vtable = mono_class_vtable (domain, array_class);
4105 if (!array_class->has_references) {
4106 o = mono_object_allocate_ptrfree (byte_len, vtable);
4107 #if NEED_TO_ZERO_PTRFREE
4108 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4110 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4111 o = mono_object_allocate_spec (byte_len, vtable);
4113 o = mono_object_allocate (byte_len, vtable);
4116 array = (MonoArray*)o;
4117 array->max_length = len;
4120 MonoArrayBounds *bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
4121 array->bounds = bounds;
4122 for (i = 0; i < array_class->rank; ++i) {
4123 bounds [i].length = lengths [i];
4125 bounds [i].lower_bound = lower_bounds [i];
4129 if (G_UNLIKELY (profile_allocs))
4130 mono_profiler_allocation (o, array_class);
4137 * @domain: domain where the object is created
4138 * @eclass: element class
4139 * @n: number of array elements
4141 * This routine creates a new szarray with @n elements of type @eclass.
4144 mono_array_new (MonoDomain *domain, MonoClass *eclass, mono_array_size_t n)
4148 MONO_ARCH_SAVE_REGS;
4150 ac = mono_array_class_get (eclass, 1);
4153 return mono_array_new_specific (mono_class_vtable (domain, ac), n);
4157 * mono_array_new_specific:
4158 * @vtable: a vtable in the appropriate domain for an initialized class
4159 * @n: number of array elements
4161 * This routine is a fast alternative to mono_array_new() for code which
4162 * can be sure about the domain it operates in.
4165 mono_array_new_specific (MonoVTable *vtable, mono_array_size_t n)
4169 guint32 byte_len, elem_size;
4171 MONO_ARCH_SAVE_REGS;
4173 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
4178 elem_size = mono_array_element_size (vtable->klass);
4179 if (CHECK_MUL_OVERFLOW_UN (n, elem_size)) {
4180 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4183 byte_len = n * elem_size;
4184 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray))) {
4185 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4188 byte_len += sizeof (MonoArray);
4189 if (!vtable->klass->has_references) {
4190 o = mono_object_allocate_ptrfree (byte_len, vtable);
4191 #if NEED_TO_ZERO_PTRFREE
4192 ((MonoArray*)o)->bounds = NULL;
4193 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4195 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4196 o = mono_object_allocate_spec (byte_len, vtable);
4198 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4199 o = mono_object_allocate (byte_len, vtable);
4202 ao = (MonoArray *)o;
4204 if (G_UNLIKELY (profile_allocs))
4205 mono_profiler_allocation (o, vtable->klass);
4211 * mono_string_new_utf16:
4212 * @text: a pointer to an utf16 string
4213 * @len: the length of the string
4215 * Returns: A newly created string object which contains @text.
4218 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
4222 s = mono_string_new_size (domain, len);
4223 g_assert (s != NULL);
4225 memcpy (mono_string_chars (s), text, len * 2);
4231 * mono_string_new_size:
4232 * @text: a pointer to an utf16 string
4233 * @len: the length of the string
4235 * Returns: A newly created string object of @len
4238 mono_string_new_size (MonoDomain *domain, gint32 len)
4242 size_t size = (sizeof (MonoString) + ((len + 1) * 2));
4244 /* overflow ? can't fit it, can't allocate it! */
4246 mono_gc_out_of_memory (-1);
4248 vtable = mono_class_vtable (domain, mono_defaults.string_class);
4250 s = mono_object_allocate_ptrfree (size, vtable);
4253 #if NEED_TO_ZERO_PTRFREE
4256 if (G_UNLIKELY (profile_allocs))
4257 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
4263 * mono_string_new_len:
4264 * @text: a pointer to an utf8 string
4265 * @length: number of bytes in @text to consider
4267 * Returns: A newly created string object which contains @text.
4270 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
4272 GError *error = NULL;
4273 MonoString *o = NULL;
4275 glong items_written;
4277 ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
4280 o = mono_string_new_utf16 (domain, ut, items_written);
4282 g_error_free (error);
4291 * @text: a pointer to an utf8 string
4293 * Returns: A newly created string object which contains @text.
4296 mono_string_new (MonoDomain *domain, const char *text)
4298 GError *error = NULL;
4299 MonoString *o = NULL;
4301 glong items_written;
4306 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
4309 o = mono_string_new_utf16 (domain, ut, items_written);
4311 g_error_free (error);
4314 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
4319 MonoString *o = NULL;
4321 if (!g_utf8_validate (text, -1, &end))
4324 len = g_utf8_strlen (text, -1);
4325 o = mono_string_new_size (domain, len);
4326 str = mono_string_chars (o);
4328 while (text < end) {
4329 *str++ = g_utf8_get_char (text);
4330 text = g_utf8_next_char (text);
4337 * mono_string_new_wrapper:
4338 * @text: pointer to utf8 characters.
4340 * Helper function to create a string object from @text in the current domain.
4343 mono_string_new_wrapper (const char *text)
4345 MonoDomain *domain = mono_domain_get ();
4347 MONO_ARCH_SAVE_REGS;
4350 return mono_string_new (domain, text);
4357 * @class: the class of the value
4358 * @value: a pointer to the unboxed data
4360 * Returns: A newly created object which contains @value.
4363 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
4369 g_assert (class->valuetype);
4370 if (mono_class_is_nullable (class))
4371 return mono_nullable_box (value, class);
4373 vtable = mono_class_vtable (domain, class);
4374 size = mono_class_instance_size (class);
4375 res = mono_object_new_alloc_specific (vtable);
4376 if (G_UNLIKELY (profile_allocs))
4377 mono_profiler_allocation (res, class);
4379 size = size - sizeof (MonoObject);
4382 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
4385 #if NO_UNALIGNED_ACCESS
4386 memcpy ((char *)res + sizeof (MonoObject), value, size);
4390 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
4393 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
4396 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
4399 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
4402 memcpy ((char *)res + sizeof (MonoObject), value, size);
4405 if (class->has_finalize)
4406 mono_object_register_finalizer (res);
4412 * @dest: destination pointer
4413 * @src: source pointer
4414 * @klass: a valuetype class
4416 * Copy a valuetype from @src to @dest. This function must be used
4417 * when @klass contains references fields.
4420 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
4422 int size = mono_class_value_size (klass, NULL);
4423 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
4424 memcpy (dest, src, size);
4428 * mono_value_copy_array:
4429 * @dest: destination array
4430 * @dest_idx: index in the @dest array
4431 * @src: source pointer
4432 * @count: number of items
4434 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
4435 * This function must be used when @klass contains references fields.
4436 * Overlap is handled.
4439 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
4441 int size = mono_array_element_size (dest->obj.vtable->klass);
4442 char *d = mono_array_addr_with_size (dest, size, dest_idx);
4443 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
4444 memmove (d, src, size * count);
4448 * mono_object_get_domain:
4449 * @obj: object to query
4451 * Returns: the MonoDomain where the object is hosted
4454 mono_object_get_domain (MonoObject *obj)
4456 return mono_object_domain (obj);
4460 * mono_object_get_class:
4461 * @obj: object to query
4463 * Returns: the MonOClass of the object.
4466 mono_object_get_class (MonoObject *obj)
4468 return mono_object_class (obj);
4471 * mono_object_get_size:
4472 * @o: object to query
4474 * Returns: the size, in bytes, of @o
4477 mono_object_get_size (MonoObject* o)
4479 MonoClass* klass = mono_object_class (o);
4480 if (klass == mono_defaults.string_class) {
4481 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
4482 } else if (o->vtable->rank) {
4483 MonoArray *array = (MonoArray*)o;
4484 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
4485 if (array->bounds) {
4488 size += sizeof (MonoArrayBounds) * o->vtable->rank;
4492 return mono_class_instance_size (klass);
4497 * mono_object_unbox:
4498 * @obj: object to unbox
4500 * Returns: a pointer to the start of the valuetype boxed in this
4503 * This method will assert if the object passed is not a valuetype.
4506 mono_object_unbox (MonoObject *obj)
4508 /* add assert for valuetypes? */
4509 g_assert (obj->vtable->klass->valuetype);
4510 return ((char*)obj) + sizeof (MonoObject);
4514 * mono_object_isinst:
4516 * @klass: a pointer to a class
4518 * Returns: @obj if @obj is derived from @klass
4521 mono_object_isinst (MonoObject *obj, MonoClass *klass)
4524 mono_class_init (klass);
4526 if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE)
4527 return mono_object_isinst_mbyref (obj, klass);
4532 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
4536 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
4545 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4546 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
4550 MonoClass *oklass = vt->klass;
4551 if ((oklass == mono_defaults.transparent_proxy_class))
4552 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
4554 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
4558 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
4560 MonoDomain *domain = mono_domain_get ();
4562 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
4563 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
4564 MonoMethod *im = NULL;
4567 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
4568 im = mono_object_get_virtual_method (rp, im);
4571 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
4574 res = mono_runtime_invoke (im, rp, pa, NULL);
4576 if (*(MonoBoolean *) mono_object_unbox(res)) {
4577 /* Update the vtable of the remote type, so it can safely cast to this new type */
4578 mono_upgrade_remote_class (domain, obj, klass);
4587 * mono_object_castclass_mbyref:
4589 * @klass: a pointer to a class
4591 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
4594 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
4596 if (!obj) return NULL;
4597 if (mono_object_isinst_mbyref (obj, klass)) return obj;
4599 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
4601 "InvalidCastException"));
4606 MonoDomain *orig_domain;
4612 str_lookup (MonoDomain *domain, gpointer user_data)
4614 LDStrInfo *info = user_data;
4615 if (info->res || domain == info->orig_domain)
4617 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
4623 mono_string_get_pinned (MonoString *str)
4627 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
4628 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
4629 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
4630 news->length = mono_string_length (str);
4635 #define mono_string_get_pinned(str) (str)
4639 mono_string_is_interned_lookup (MonoString *str, int insert)
4641 MonoGHashTable *ldstr_table;
4645 domain = ((MonoObject *)str)->vtable->domain;
4646 ldstr_table = domain->ldstr_table;
4648 if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
4653 str = mono_string_get_pinned (str);
4654 mono_g_hash_table_insert (ldstr_table, str, str);
4658 LDStrInfo ldstr_info;
4659 ldstr_info.orig_domain = domain;
4660 ldstr_info.ins = str;
4661 ldstr_info.res = NULL;
4663 mono_domain_foreach (str_lookup, &ldstr_info);
4664 if (ldstr_info.res) {
4666 * the string was already interned in some other domain:
4667 * intern it in the current one as well.
4669 mono_g_hash_table_insert (ldstr_table, str, str);
4679 * mono_string_is_interned:
4680 * @o: String to probe
4682 * Returns whether the string has been interned.
4685 mono_string_is_interned (MonoString *o)
4687 return mono_string_is_interned_lookup (o, FALSE);
4691 * mono_string_intern:
4692 * @o: String to intern
4694 * Interns the string passed.
4695 * Returns: The interned string.
4698 mono_string_intern (MonoString *str)
4700 return mono_string_is_interned_lookup (str, TRUE);
4705 * @domain: the domain where the string will be used.
4706 * @image: a metadata context
4707 * @idx: index into the user string table.
4709 * Implementation for the ldstr opcode.
4710 * Returns: a loaded string from the @image/@idx combination.
4713 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
4715 MONO_ARCH_SAVE_REGS;
4718 return mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
4720 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
4724 * mono_ldstr_metadata_sig
4725 * @domain: the domain for the string
4726 * @sig: the signature of a metadata string
4728 * Returns: a MonoString for a string stored in the metadata
4731 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
4733 const char *str = sig;
4734 MonoString *o, *interned;
4737 len2 = mono_metadata_decode_blob_size (str, &str);
4740 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
4741 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
4744 guint16 *p2 = (guint16*)mono_string_chars (o);
4745 for (i = 0; i < len2; ++i) {
4746 *p2 = GUINT16_FROM_LE (*p2);
4752 if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
4754 /* o will get garbage collected */
4758 o = mono_string_get_pinned (o);
4759 mono_g_hash_table_insert (domain->ldstr_table, o, o);
4766 * mono_string_to_utf8:
4767 * @s: a System.String
4769 * Return the UTF8 representation for @s.
4770 * the resulting buffer nedds to be freed with g_free().
4773 mono_string_to_utf8 (MonoString *s)
4777 GError *error = NULL;
4783 return g_strdup ("");
4785 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &error);
4787 MonoException *exc = mono_get_exception_argument ("string", error->message);
4788 g_error_free (error);
4789 mono_raise_exception(exc);
4791 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
4792 if (s->length > written) {
4793 /* allocate the total length and copy the part of the string that has been converted */
4794 char *as2 = g_malloc0 (s->length);
4795 memcpy (as2, as, written);
4804 * mono_string_to_utf16:
4807 * Return an null-terminated array of the utf-16 chars
4808 * contained in @s. The result must be freed with g_free().
4809 * This is a temporary helper until our string implementation
4810 * is reworked to always include the null terminating char.
4813 mono_string_to_utf16 (MonoString *s)
4820 as = g_malloc ((s->length * 2) + 2);
4821 as [(s->length * 2)] = '\0';
4822 as [(s->length * 2) + 1] = '\0';
4825 return (gunichar2 *)(as);
4828 memcpy (as, mono_string_chars(s), s->length * 2);
4829 return (gunichar2 *)(as);
4833 * mono_string_from_utf16:
4834 * @data: the UTF16 string (LPWSTR) to convert
4836 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
4838 * Returns: a MonoString.
4841 mono_string_from_utf16 (gunichar2 *data)
4843 MonoDomain *domain = mono_domain_get ();
4849 while (data [len]) len++;
4851 return mono_string_new_utf16 (domain, data, len);
4856 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s)
4863 return mono_string_to_utf8 (s);
4865 r = mono_string_to_utf8 (s);
4869 len = strlen (r) + 1;
4871 mp_s = mono_mempool_alloc (mp, len);
4873 mp_s = mono_image_alloc (image, len);
4875 memcpy (mp_s, r, len);
4883 * mono_string_to_utf8_image:
4884 * @s: a System.String
4886 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
4889 mono_string_to_utf8_image (MonoImage *image, MonoString *s)
4891 return mono_string_to_utf8_internal (NULL, image, s);
4895 * mono_string_to_utf8_mp:
4896 * @s: a System.String
4898 * Same as mono_string_to_utf8, but allocate the string from a mempool.
4901 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s)
4903 return mono_string_to_utf8_internal (mp, NULL, s);
4907 default_ex_handler (MonoException *ex)
4909 MonoObject *o = (MonoObject*)ex;
4910 g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
4914 static MonoExceptionFunc ex_handler = default_ex_handler;
4917 * mono_install_handler:
4918 * @func: exception handler
4920 * This is an internal JIT routine used to install the handler for exceptions
4924 mono_install_handler (MonoExceptionFunc func)
4926 ex_handler = func? func: default_ex_handler;
4930 * mono_raise_exception:
4931 * @ex: exception object
4933 * Signal the runtime that the exception @ex has been raised in unmanaged code.
4936 mono_raise_exception (MonoException *ex)
4939 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
4940 * that will cause gcc to omit the function epilog, causing problems when
4941 * the JIT tries to walk the stack, since the return address on the stack
4942 * will point into the next function in the executable, not this one.
4945 if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class) {
4946 MonoThread *thread = mono_thread_current ();
4947 g_assert (ex->object.vtable->domain == mono_domain_get ());
4948 MONO_OBJECT_SETREF (thread, abort_exc, ex);
4955 * mono_wait_handle_new:
4956 * @domain: Domain where the object will be created
4957 * @handle: Handle for the wait handle
4959 * Returns: A new MonoWaitHandle created in the given domain for the given handle
4962 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
4964 MonoWaitHandle *res;
4965 gpointer params [1];
4966 static MonoMethod *handle_set;
4968 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.waithandle_class);
4970 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
4972 handle_set = mono_class_get_property_from_name (mono_defaults.waithandle_class, "Handle")->set;
4974 params [0] = &handle;
4975 mono_runtime_invoke (handle_set, res, params, NULL);
4981 mono_wait_handle_get_handle (MonoWaitHandle *handle)
4983 static MonoClassField *f_os_handle;
4984 static MonoClassField *f_safe_handle;
4986 if (!f_os_handle && !f_safe_handle) {
4987 f_os_handle = mono_class_get_field_from_name (mono_defaults.waithandle_class, "os_handle");
4988 f_safe_handle = mono_class_get_field_from_name (mono_defaults.waithandle_class, "safe_wait_handle");
4993 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
4997 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
5004 mono_runtime_capture_context (MonoDomain *domain)
5006 RuntimeInvokeFunction runtime_invoke;
5008 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
5009 MonoMethod *method = mono_get_context_capture_method ();
5010 MonoMethod *wrapper;
5013 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
5014 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
5015 domain->capture_context_method = mono_compile_method (method);
5018 runtime_invoke = domain->capture_context_runtime_invoke;
5020 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
5023 * mono_async_result_new:
5024 * @domain:domain where the object will be created.
5025 * @handle: wait handle.
5026 * @state: state to pass to AsyncResult
5027 * @data: C closure data.
5029 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
5030 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
5034 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
5036 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
5037 MonoObject *context = mono_runtime_capture_context (domain);
5038 /* we must capture the execution context from the original thread */
5040 MONO_OBJECT_SETREF (res, execution_context, context);
5041 /* note: result may be null if the flow is suppressed */
5045 MONO_OBJECT_SETREF (res, object_data, object_data);
5046 MONO_OBJECT_SETREF (res, async_state, state);
5048 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
5050 res->sync_completed = FALSE;
5051 res->completed = FALSE;
5057 mono_message_init (MonoDomain *domain,
5058 MonoMethodMessage *this,
5059 MonoReflectionMethod *method,
5060 MonoArray *out_args)
5062 static MonoClass *object_array_klass;
5063 static MonoClass *byte_array_klass;
5064 static MonoClass *string_array_klass;
5065 MonoMethodSignature *sig = mono_method_signature (method->method);
5071 if (!object_array_klass) {
5074 klass = mono_array_class_get (mono_defaults.object_class, 1);
5077 mono_memory_barrier ();
5078 object_array_klass = klass;
5080 klass = mono_array_class_get (mono_defaults.byte_class, 1);
5083 mono_memory_barrier ();
5084 byte_array_klass = klass;
5086 klass = mono_array_class_get (mono_defaults.string_class, 1);
5089 mono_memory_barrier ();
5090 string_array_klass = klass;
5093 MONO_OBJECT_SETREF (this, method, method);
5095 MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
5096 MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
5097 this->async_result = NULL;
5098 this->call_type = CallType_Sync;
5100 names = g_new (char *, sig->param_count);
5101 mono_method_get_param_names (method->method, (const char **) names);
5102 MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
5104 for (i = 0; i < sig->param_count; i++) {
5105 name = mono_string_new (domain, names [i]);
5106 mono_array_setref (this->names, i, name);
5110 for (i = 0, j = 0; i < sig->param_count; i++) {
5111 if (sig->params [i]->byref) {
5113 MonoObject* arg = mono_array_get (out_args, gpointer, j);
5114 mono_array_setref (this->args, i, arg);
5118 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
5122 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
5125 mono_array_set (this->arg_types, guint8, i, arg_type);
5130 * mono_remoting_invoke:
5131 * @real_proxy: pointer to a RealProxy object
5132 * @msg: The MonoMethodMessage to execute
5133 * @exc: used to store exceptions
5134 * @out_args: used to store output arguments
5136 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
5137 * IMessage interface and it is not trivial to extract results from there. So
5138 * we call an helper method PrivateInvoke instead of calling
5139 * RealProxy::Invoke() directly.
5141 * Returns: the result object.
5144 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
5145 MonoObject **exc, MonoArray **out_args)
5147 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
5150 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
5153 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
5155 real_proxy->vtable->domain->private_invoke_method = im;
5158 pa [0] = real_proxy;
5163 return mono_runtime_invoke (im, NULL, pa, exc);
5167 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
5168 MonoObject **exc, MonoArray **out_args)
5170 static MonoClass *object_array_klass;
5173 MonoMethodSignature *sig;
5175 int i, j, outarg_count = 0;
5177 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5179 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
5180 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5181 target = tp->rp->unwrapped_server;
5183 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
5187 domain = mono_domain_get ();
5188 method = msg->method->method;
5189 sig = mono_method_signature (method);
5191 for (i = 0; i < sig->param_count; i++) {
5192 if (sig->params [i]->byref)
5196 if (!object_array_klass) {
5199 klass = mono_array_class_get (mono_defaults.object_class, 1);
5202 mono_memory_barrier ();
5203 object_array_klass = klass;
5206 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
5207 *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
5210 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
5212 for (i = 0, j = 0; i < sig->param_count; i++) {
5213 if (sig->params [i]->byref) {
5215 arg = mono_array_get (msg->args, gpointer, i);
5216 mono_array_setref (*out_args, j, arg);
5225 * mono_print_unhandled_exception:
5226 * @exc: The exception
5228 * Prints the unhandled exception.
5231 mono_print_unhandled_exception (MonoObject *exc)
5233 char *message = (char *) "";
5237 gboolean free_message = FALSE;
5239 if (mono_object_isinst (exc, mono_defaults.exception_class)) {
5240 klass = exc->vtable->klass;
5242 while (klass && method == NULL) {
5243 method = mono_class_get_method_from_name_flags (klass, "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
5245 klass = klass->parent;
5250 str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL);
5252 message = mono_string_to_utf8 (str);
5253 free_message = TRUE;
5258 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
5259 * exc->vtable->klass->name, message);
5261 g_printerr ("\nUnhandled Exception: %s\n", message);
5268 * mono_delegate_ctor:
5269 * @this: pointer to an uninitialized delegate object
5270 * @target: target object
5271 * @addr: pointer to native code
5274 * Initialize a delegate and sets a specific method, not the one
5275 * associated with addr. This is useful when sharing generic code.
5276 * In that case addr will most probably not be associated with the
5277 * correct instantiation of the method.
5280 mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer addr, MonoMethod *method)
5282 MonoDelegate *delegate = (MonoDelegate *)this;
5289 delegate->method = method;
5291 class = this->vtable->klass;
5292 mono_stats.delegate_creations++;
5294 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5296 method = mono_marshal_get_remoting_invoke (method);
5297 delegate->method_ptr = mono_compile_method (method);
5298 MONO_OBJECT_SETREF (delegate, target, target);
5299 } else if (mono_method_signature (method)->hasthis && method->klass->valuetype) {
5300 method = mono_marshal_get_unbox_wrapper (method);
5301 delegate->method_ptr = mono_compile_method (method);
5302 MONO_OBJECT_SETREF (delegate, target, target);
5304 delegate->method_ptr = addr;
5305 MONO_OBJECT_SETREF (delegate, target, target);
5308 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->klass);
5312 * mono_delegate_ctor:
5313 * @this: pointer to an uninitialized delegate object
5314 * @target: target object
5315 * @addr: pointer to native code
5317 * This is used to initialize a delegate.
5320 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
5322 MonoDomain *domain = mono_domain_get ();
5324 MonoMethod *method = NULL;
5328 if ((ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr)))) {
5329 method = ji->method;
5330 g_assert (!method->klass->generic_container);
5333 mono_delegate_ctor_with_method (this, target, addr, method);
5337 * mono_method_call_message_new:
5338 * @method: method to encapsulate
5339 * @params: parameters to the method
5340 * @invoke: optional, delegate invoke.
5341 * @cb: async callback delegate.
5342 * @state: state passed to the async callback.
5344 * Translates arguments pointers into a MonoMethodMessage.
5347 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
5348 MonoDelegate **cb, MonoObject **state)
5350 MonoDomain *domain = mono_domain_get ();
5351 MonoMethodSignature *sig = mono_method_signature (method);
5352 MonoMethodMessage *msg;
5355 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5358 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
5359 count = sig->param_count - 2;
5361 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
5362 count = sig->param_count;
5365 for (i = 0; i < count; i++) {
5370 if (sig->params [i]->byref)
5371 vpos = *((gpointer *)params [i]);
5375 type = sig->params [i]->type;
5376 class = mono_class_from_mono_type (sig->params [i]);
5378 if (class->valuetype)
5379 arg = mono_value_box (domain, class, vpos);
5381 arg = *((MonoObject **)vpos);
5383 mono_array_setref (msg->args, i, arg);
5386 if (cb != NULL && state != NULL) {
5387 *cb = *((MonoDelegate **)params [i]);
5389 *state = *((MonoObject **)params [i]);
5396 * mono_method_return_message_restore:
5398 * Restore results from message based processing back to arguments pointers
5401 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
5403 MonoMethodSignature *sig = mono_method_signature (method);
5404 int i, j, type, size, out_len;
5406 if (out_args == NULL)
5408 out_len = mono_array_length (out_args);
5412 for (i = 0, j = 0; i < sig->param_count; i++) {
5413 MonoType *pt = sig->params [i];
5418 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
5420 arg = mono_array_get (out_args, gpointer, j);
5424 case MONO_TYPE_VOID:
5425 g_assert_not_reached ();
5429 case MONO_TYPE_BOOLEAN:
5432 case MONO_TYPE_CHAR:
5439 case MONO_TYPE_VALUETYPE: {
5441 size = mono_class_value_size (((MonoObject*)arg)->vtable->klass, NULL);
5442 memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
5445 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
5446 memset (*((gpointer *)params [i]), 0, size);
5450 case MONO_TYPE_STRING:
5451 case MONO_TYPE_CLASS:
5452 case MONO_TYPE_ARRAY:
5453 case MONO_TYPE_SZARRAY:
5454 case MONO_TYPE_OBJECT:
5455 **((MonoObject ***)params [i]) = (MonoObject *)arg;
5458 g_assert_not_reached ();
5467 * mono_load_remote_field:
5468 * @this: pointer to an object
5469 * @klass: klass of the object containing @field
5470 * @field: the field to load
5471 * @res: a storage to store the result
5473 * This method is called by the runtime on attempts to load fields of
5474 * transparent proxy objects. @this points to such TP, @klass is the class of
5475 * the object containing @field. @res is a storage location which can be
5476 * used to store the result.
5478 * Returns: an address pointing to the value of field.
5481 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
5483 static MonoMethod *getter = NULL;
5484 MonoDomain *domain = mono_domain_get ();
5485 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5486 MonoClass *field_class;
5487 MonoMethodMessage *msg;
5488 MonoArray *out_args;
5492 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5493 g_assert (res != NULL);
5495 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5496 mono_field_get_value (tp->rp->unwrapped_server, field, res);
5501 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
5505 field_class = mono_class_from_mono_type (field->type);
5507 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5508 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
5509 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
5511 full_name = mono_type_get_full_name (klass);
5512 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5513 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5516 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5518 if (exc) mono_raise_exception ((MonoException *)exc);
5520 if (mono_array_length (out_args) == 0)
5523 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
5525 if (field_class->valuetype) {
5526 return ((char *)*res) + sizeof (MonoObject);
5532 * mono_load_remote_field_new:
5537 * Missing documentation.
5540 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
5542 static MonoMethod *getter = NULL;
5543 MonoDomain *domain = mono_domain_get ();
5544 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5545 MonoClass *field_class;
5546 MonoMethodMessage *msg;
5547 MonoArray *out_args;
5548 MonoObject *exc, *res;
5551 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5553 field_class = mono_class_from_mono_type (field->type);
5555 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5557 if (field_class->valuetype) {
5558 res = mono_object_new (domain, field_class);
5559 val = ((gchar *) res) + sizeof (MonoObject);
5563 mono_field_get_value (tp->rp->unwrapped_server, field, val);
5568 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
5572 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5573 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
5575 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
5577 full_name = mono_type_get_full_name (klass);
5578 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5579 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5582 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5584 if (exc) mono_raise_exception ((MonoException *)exc);
5586 if (mono_array_length (out_args) == 0)
5589 res = mono_array_get (out_args, MonoObject *, 0);
5595 * mono_store_remote_field:
5596 * @this: pointer to an object
5597 * @klass: klass of the object containing @field
5598 * @field: the field to load
5599 * @val: the value/object to store
5601 * This method is called by the runtime on attempts to store fields of
5602 * transparent proxy objects. @this points to such TP, @klass is the class of
5603 * the object containing @field. @val is the new value to store in @field.
5606 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
5608 static MonoMethod *setter = NULL;
5609 MonoDomain *domain = mono_domain_get ();
5610 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5611 MonoClass *field_class;
5612 MonoMethodMessage *msg;
5613 MonoArray *out_args;
5618 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5620 field_class = mono_class_from_mono_type (field->type);
5622 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5623 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
5624 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
5629 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
5633 if (field_class->valuetype)
5634 arg = mono_value_box (domain, field_class, val);
5636 arg = *((MonoObject **)val);
5639 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5640 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
5642 full_name = mono_type_get_full_name (klass);
5643 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5644 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5645 mono_array_setref (msg->args, 2, arg);
5648 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5650 if (exc) mono_raise_exception ((MonoException *)exc);
5654 * mono_store_remote_field_new:
5660 * Missing documentation
5663 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
5665 static MonoMethod *setter = NULL;
5666 MonoDomain *domain = mono_domain_get ();
5667 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5668 MonoClass *field_class;
5669 MonoMethodMessage *msg;
5670 MonoArray *out_args;
5674 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5676 field_class = mono_class_from_mono_type (field->type);
5678 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5679 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
5680 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
5685 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
5689 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5690 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
5692 full_name = mono_type_get_full_name (klass);
5693 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5694 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5695 mono_array_setref (msg->args, 2, arg);
5698 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5700 if (exc) mono_raise_exception ((MonoException *)exc);
5704 * mono_create_ftnptr:
5706 * Given a function address, create a function descriptor for it.
5707 * This is only needed on IA64 and PPC64.
5710 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
5715 desc = mono_domain_code_reserve (domain, 2 * sizeof (gpointer));
5721 #elif defined(__ppc64__) || defined(__powerpc64__)
5724 desc = mono_domain_alloc0 (domain, 3 * sizeof (gpointer));
5737 * mono_get_addr_from_ftnptr:
5739 * Given a pointer to a function descriptor, return the function address.
5740 * This is only needed on IA64 and PPC64.
5743 mono_get_addr_from_ftnptr (gpointer descr)
5745 #if defined(__ia64__) || defined(__ppc64__) || defined(__powerpc64__)
5746 return *(gpointer*)descr;
5754 * mono_string_chars:
5757 * Returns a pointer to the UCS16 characters stored in the MonoString
5760 mono_string_chars(MonoString *s)
5762 /* This method is here only for documentation extraction, this is a macro */
5766 * mono_string_length:
5769 * Returns the lenght in characters of the string
5772 mono_string_length (MonoString *s)
5774 /* This method is here only for documentation extraction, this is a macro */