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_free_method (method);
586 * The vtables in the root appdomain are assumed to be reachable by other
587 * roots, and we don't use typed allocation in the other domains.
590 /* The sync block is no longer a GC pointer */
591 #define GC_HEADER_BITMAP (0)
593 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
596 compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
598 MonoClassField *field;
604 max_size = mono_class_data_size (class) / sizeof (gpointer);
606 max_size = class->instance_size / sizeof (gpointer);
607 if (max_size >= size) {
608 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
611 for (p = class; p != NULL; p = p->parent) {
612 gpointer iter = NULL;
613 while ((field = mono_class_get_fields (p, &iter))) {
617 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
619 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
622 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
625 /* FIXME: should not happen, flag as type load error */
626 if (field->type->byref)
629 pos = field->offset / sizeof (gpointer);
632 type = mono_type_get_underlying_type (field->type);
633 switch (type->type) {
636 case MONO_TYPE_FNPTR:
638 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
643 if (class->image != mono_defaults.corlib)
646 case MONO_TYPE_STRING:
647 case MONO_TYPE_SZARRAY:
648 case MONO_TYPE_CLASS:
649 case MONO_TYPE_OBJECT:
650 case MONO_TYPE_ARRAY:
651 g_assert ((field->offset % sizeof(gpointer)) == 0);
653 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
654 *max_set = MAX (*max_set, pos);
656 case MONO_TYPE_GENERICINST:
657 if (!mono_type_generic_inst_is_valuetype (type)) {
658 g_assert ((field->offset % sizeof(gpointer)) == 0);
660 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
661 *max_set = MAX (*max_set, pos);
666 case MONO_TYPE_VALUETYPE: {
667 MonoClass *fclass = mono_class_from_mono_type (field->type);
668 if (fclass->has_references) {
669 /* remove the object header */
670 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
684 case MONO_TYPE_BOOLEAN:
688 g_assert_not_reached ();
700 * similar to the above, but sets the bits in the bitmap for any non-ref field
701 * and ignores static fields
704 compute_class_non_ref_bitmap (MonoClass *class, gsize *bitmap, int size, int offset)
706 MonoClassField *field;
711 max_size = class->instance_size / sizeof (gpointer);
712 if (max_size >= size) {
713 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
716 for (p = class; p != NULL; p = p->parent) {
717 gpointer iter = NULL;
718 while ((field = mono_class_get_fields (p, &iter))) {
721 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
723 /* FIXME: should not happen, flag as type load error */
724 if (field->type->byref)
727 pos = field->offset / sizeof (gpointer);
730 type = mono_type_get_underlying_type (field->type);
731 switch (type->type) {
732 #if SIZEOF_VOID_P == 8
736 case MONO_TYPE_FNPTR:
741 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
742 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
743 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
746 #if SIZEOF_VOID_P == 4
750 case MONO_TYPE_FNPTR:
755 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
756 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
757 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
763 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
764 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
765 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
768 case MONO_TYPE_BOOLEAN:
771 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
773 case MONO_TYPE_STRING:
774 case MONO_TYPE_SZARRAY:
775 case MONO_TYPE_CLASS:
776 case MONO_TYPE_OBJECT:
777 case MONO_TYPE_ARRAY:
779 case MONO_TYPE_GENERICINST:
780 if (!mono_type_generic_inst_is_valuetype (type)) {
785 case MONO_TYPE_VALUETYPE: {
786 MonoClass *fclass = mono_class_from_mono_type (field->type);
787 /* remove the object header */
788 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
792 g_assert_not_reached ();
801 * mono_class_insecure_overlapping:
802 * check if a class with explicit layout has references and non-references
803 * fields overlapping.
805 * Returns: TRUE if it is insecure to load the type.
808 mono_class_insecure_overlapping (MonoClass *klass)
812 gsize default_bitmap [4] = {0};
814 gsize default_nrbitmap [4] = {0};
815 int i, insecure = FALSE;
818 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
819 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
821 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
822 int idx = i % (sizeof (bitmap [0]) * 8);
823 if (bitmap [idx] & nrbitmap [idx]) {
828 if (bitmap != default_bitmap)
830 if (nrbitmap != default_nrbitmap)
833 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
841 mono_string_alloc (int length)
843 return mono_string_new_size (mono_domain_get (), length);
847 mono_class_compute_gc_descriptor (MonoClass *class)
851 gsize default_bitmap [4] = {0};
852 static gboolean gcj_inited = FALSE;
857 mono_register_jit_icall (mono_object_new_ptrfree, "mono_object_new_ptrfree", mono_create_icall_signature ("object ptr"), FALSE);
858 mono_register_jit_icall (mono_object_new_ptrfree_box, "mono_object_new_ptrfree_box", mono_create_icall_signature ("object ptr"), FALSE);
859 mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
860 mono_register_jit_icall (mono_string_alloc, "mono_string_alloc", mono_create_icall_signature ("object int"), FALSE);
862 #ifdef HAVE_GC_GCJ_MALLOC
864 * This is not needed unless the relevant code in mono_get_allocation_ftn () is
868 #ifdef GC_REDIRECT_TO_LOCAL
869 mono_register_jit_icall (GC_local_gcj_malloc, "GC_local_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
870 mono_register_jit_icall (GC_local_gcj_fast_malloc, "GC_local_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
872 mono_register_jit_icall (GC_gcj_malloc, "GC_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
873 mono_register_jit_icall (GC_gcj_fast_malloc, "GC_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
878 mono_loader_unlock ();
882 mono_class_init (class);
884 if (class->gc_descr_inited)
887 class->gc_descr_inited = TRUE;
888 class->gc_descr = GC_NO_DESCRIPTOR;
890 bitmap = default_bitmap;
891 if (class == mono_defaults.string_class) {
892 class->gc_descr = (gpointer)mono_gc_make_descr_for_string (bitmap, 2);
893 } else if (class->rank) {
894 mono_class_compute_gc_descriptor (class->element_class);
895 if (!class->element_class->valuetype) {
897 class->gc_descr = mono_gc_make_descr_for_array (TRUE, &abm, 1, sizeof (gpointer));
898 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
899 class->name_space, class->name);*/
901 /* remove the object header */
902 bitmap = compute_class_bitmap (class->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
903 class->gc_descr = mono_gc_make_descr_for_array (TRUE, bitmap, mono_array_element_size (class) / sizeof (gpointer), mono_array_element_size (class));
904 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
905 class->name_space, class->name);*/
906 if (bitmap != default_bitmap)
910 /*static int count = 0;
913 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
914 class->gc_descr = (gpointer)mono_gc_make_descr_for_object (bitmap, max_set + 1, class->instance_size);
916 if (class->gc_descr == GC_NO_DESCRIPTOR)
917 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
919 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
920 if (bitmap != default_bitmap)
926 * field_is_special_static:
927 * @fklass: The MonoClass to look up.
928 * @field: The MonoClassField describing the field.
930 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
931 * SPECIAL_STATIC_NONE otherwise.
934 field_is_special_static (MonoClass *fklass, MonoClassField *field)
936 MonoCustomAttrInfo *ainfo;
938 ainfo = mono_custom_attrs_from_field (fklass, field);
941 for (i = 0; i < ainfo->num_attrs; ++i) {
942 MonoClass *klass = ainfo->attrs [i].ctor->klass;
943 if (klass->image == mono_defaults.corlib) {
944 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
945 mono_custom_attrs_free (ainfo);
946 return SPECIAL_STATIC_THREAD;
948 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
949 mono_custom_attrs_free (ainfo);
950 return SPECIAL_STATIC_CONTEXT;
954 mono_custom_attrs_free (ainfo);
955 return SPECIAL_STATIC_NONE;
958 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
959 #define mix(a,b,c) { \
960 a -= c; a ^= rot(c, 4); c += b; \
961 b -= a; b ^= rot(a, 6); a += c; \
962 c -= b; c ^= rot(b, 8); b += a; \
963 a -= c; a ^= rot(c,16); c += b; \
964 b -= a; b ^= rot(a,19); a += c; \
965 c -= b; c ^= rot(b, 4); b += a; \
967 #define final(a,b,c) { \
968 c ^= b; c -= rot(b,14); \
969 a ^= c; a -= rot(c,11); \
970 b ^= a; b -= rot(a,25); \
971 c ^= b; c -= rot(b,16); \
972 a ^= c; a -= rot(c,4); \
973 b ^= a; b -= rot(a,14); \
974 c ^= b; c -= rot(b,24); \
978 mono_method_get_imt_slot (MonoMethod *method) {
979 MonoMethodSignature *sig;
981 guint32 *hashes_start, *hashes;
986 * We do this to simplify generic sharing. It will hurt
987 * performance in cases where a class implements two different
988 * instantiations of the same generic interface.
989 * The code in build_imt_slots () depends on this.
991 if (method->is_inflated)
992 method = ((MonoMethodInflated*)method)->declaring;
994 sig = mono_method_signature (method);
995 hashes_count = sig->param_count + 4;
996 hashes_start = malloc (hashes_count * sizeof (guint32));
997 hashes = hashes_start;
999 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1000 printf ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod\n",
1001 method->klass->name_space, method->klass->name, method->name);
1002 g_assert_not_reached ();
1005 /* Initialize hashes */
1006 hashes [0] = g_str_hash (method->klass->name);
1007 hashes [1] = g_str_hash (method->klass->name_space);
1008 hashes [2] = g_str_hash (method->name);
1009 hashes [3] = mono_metadata_type_hash (sig->ret);
1010 for (i = 0; i < sig->param_count; i++) {
1011 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1014 /* Setup internal state */
1015 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1017 /* Handle most of the hashes */
1018 while (hashes_count > 3) {
1027 /* Handle the last 3 hashes (all the case statements fall through) */
1028 switch (hashes_count) {
1029 case 3 : c += hashes [2];
1030 case 2 : b += hashes [1];
1031 case 1 : a += hashes [0];
1033 case 0: /* nothing left to add */
1037 free (hashes_start);
1038 /* Report the result */
1039 return c % MONO_IMT_SIZE;
1048 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1049 guint32 imt_slot = mono_method_get_imt_slot (method);
1050 MonoImtBuilderEntry *entry;
1052 if (slot_num >= 0 && imt_slot != slot_num) {
1053 /* we build just a single imt slot and this is not it */
1057 entry = malloc (sizeof (MonoImtBuilderEntry));
1058 entry->key = method;
1059 entry->value.vtable_slot = vtable_slot;
1060 entry->next = imt_builder [imt_slot];
1061 if (imt_builder [imt_slot] != NULL) {
1062 entry->children = imt_builder [imt_slot]->children + 1;
1063 if (entry->children == 1) {
1064 mono_stats.imt_slots_with_collisions++;
1065 *imt_collisions_bitmap |= (1 << imt_slot);
1068 entry->children = 0;
1069 mono_stats.imt_used_slots++;
1071 imt_builder [imt_slot] = entry;
1073 printf ("Added IMT slot for method (%p) %s.%s.%s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1074 method, method->klass->name_space, method->klass->name,
1075 method->name, imt_slot, vtable_slot, entry->children);
1081 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1083 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1087 e->method->klass->name_space,
1088 e->method->klass->name,
1091 printf (" * %s: NULL\n", message);
1097 compare_imt_builder_entries (const void *p1, const void *p2) {
1098 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1099 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1101 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1105 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1107 int count = end - start;
1108 int chunk_start = out_array->len;
1111 for (i = start; i < end; ++i) {
1112 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1113 item->key = sorted_array [i]->key;
1114 item->value = sorted_array [i]->value;
1115 item->is_equals = TRUE;
1117 item->check_target_idx = out_array->len + 1;
1119 item->check_target_idx = 0;
1120 g_ptr_array_add (out_array, item);
1123 int middle = start + count / 2;
1124 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1126 item->key = sorted_array [middle]->key;
1127 item->is_equals = FALSE;
1128 g_ptr_array_add (out_array, item);
1129 imt_emit_ir (sorted_array, start, middle, out_array);
1130 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1136 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1137 int number_of_entries = entries->children + 1;
1138 MonoImtBuilderEntry **sorted_array = malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1139 GPtrArray *result = g_ptr_array_new ();
1140 MonoImtBuilderEntry *current_entry;
1143 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1144 sorted_array [i] = current_entry;
1146 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1148 /*for (i = 0; i < number_of_entries; i++) {
1149 print_imt_entry (" sorted array:", sorted_array [i], i);
1152 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1154 free (sorted_array);
1159 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry) {
1160 if (imt_builder_entry != NULL) {
1161 if (imt_builder_entry->children == 0) {
1162 /* No collision, return the vtable slot contents */
1163 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1165 /* Collision, build the thunk */
1166 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1169 result = imt_thunk_builder (vtable, domain,
1170 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, NULL);
1171 for (i = 0; i < imt_ir->len; ++i)
1172 g_free (g_ptr_array_index (imt_ir, i));
1173 g_ptr_array_free (imt_ir, TRUE);
1183 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num) {
1186 guint32 imt_collisions_bitmap = 0;
1187 MonoImtBuilderEntry **imt_builder = calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1188 int method_count = 0;
1189 gboolean record_method_count_for_max_collisions = FALSE;
1192 printf ("Building IMT for class %s.%s\n", klass->name_space, klass->name);
1194 for (i = 0; i < klass->interface_offsets_count; ++i) {
1195 MonoClass *iface = klass->interfaces_packed [i];
1196 int interface_offset = klass->interface_offsets_packed [i];
1197 int method_slot_in_interface;
1198 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1201 if (slot_num >= 0 && iface->is_inflated) {
1203 * The imt slot of the method is the same as for its declaring method,
1204 * see the comment in mono_method_get_imt_slot (), so we can
1205 * avoid inflating methods which will be discarded by
1206 * add_imt_builder_entry anyway.
1208 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1209 if (mono_method_get_imt_slot (method) != slot_num)
1212 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1213 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1216 if (extra_interfaces) {
1217 int interface_offset = klass->vtable_size;
1219 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1220 MonoClass* iface = list_item->data;
1221 int method_slot_in_interface;
1222 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1223 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1224 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1226 interface_offset += iface->method.count;
1229 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1230 /* overwrite the imt slot only if we're building all the entries or if
1231 * we're uilding this specific one
1233 if (slot_num < 0 || i == slot_num)
1234 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i]);
1236 printf ("initialize_imt_slot[%d]: %p\n", i, imt [i]);
1238 if (imt_builder [i] != NULL) {
1239 int methods_in_slot = imt_builder [i]->children + 1;
1240 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1241 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1242 record_method_count_for_max_collisions = TRUE;
1244 method_count += methods_in_slot;
1248 mono_stats.imt_number_of_methods += method_count;
1249 if (record_method_count_for_max_collisions) {
1250 mono_stats.imt_method_count_when_max_collisions = method_count;
1253 for (i = 0; i < MONO_IMT_SIZE; i++) {
1254 MonoImtBuilderEntry* entry = imt_builder [i];
1255 while (entry != NULL) {
1256 MonoImtBuilderEntry* next = entry->next;
1262 /* we OR the bitmap since we may build just a single imt slot at a time */
1263 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1267 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1268 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1271 static gpointer imt_trampoline = NULL;
1274 mono_install_imt_trampoline (gpointer tramp_code)
1276 imt_trampoline = tramp_code;
1279 static gpointer vtable_trampoline = NULL;
1282 mono_install_vtable_trampoline (gpointer tramp_code)
1284 vtable_trampoline = tramp_code;
1288 * mono_vtable_build_imt_slot:
1289 * @vtable: virtual object table struct
1290 * @imt_slot: slot in the IMT table
1292 * Fill the given @imt_slot in the IMT table of @vtable with
1293 * a trampoline or a thunk for the case of collisions.
1294 * This is part of the internal mono API.
1297 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1299 gpointer *imt = (gpointer*)vtable;
1300 imt -= MONO_IMT_SIZE;
1301 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1303 /* no support for extra interfaces: the proxy objects will need
1304 * to build the complete IMT
1305 * Update and heck needs to ahppen inside the proper domain lock, as all
1306 * the changes made to a MonoVTable.
1308 mono_domain_lock (vtable->domain);
1309 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1310 if (imt [imt_slot] == imt_trampoline)
1311 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1312 mono_domain_unlock (vtable->domain);
1317 * The first two free list entries both belong to the wait list: The
1318 * first entry is the pointer to the head of the list and the second
1319 * entry points to the last element. That way appending and removing
1320 * the first element are both O(1) operations.
1322 #define NUM_FREE_LISTS 12
1323 #define FIRST_FREE_LIST_SIZE 64
1324 #define MAX_WAIT_LENGTH 50
1325 #define THUNK_THRESHOLD 10
1328 * LOCKING: The domain lock must be held.
1331 init_thunk_free_lists (MonoDomain *domain)
1333 if (domain->thunk_free_lists)
1335 domain->thunk_free_lists = mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1339 list_index_for_size (int item_size)
1342 int size = FIRST_FREE_LIST_SIZE;
1344 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1353 * mono_method_alloc_generic_virtual_thunk:
1355 * @size: size in bytes
1357 * Allocs size bytes to be used for the code of a generic virtual
1358 * thunk. It's either allocated from the domain's code manager or
1359 * reused from a previously invalidated piece.
1361 * LOCKING: The domain lock must be held.
1364 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1366 static gboolean inited = FALSE;
1367 static int generic_virtual_thunks_size = 0;
1371 MonoThunkFreeList **l;
1373 init_thunk_free_lists (domain);
1375 size += sizeof (guint32);
1376 if (size < sizeof (MonoThunkFreeList))
1377 size = sizeof (MonoThunkFreeList);
1379 i = list_index_for_size (size);
1380 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1381 if ((*l)->size >= size) {
1382 MonoThunkFreeList *item = *l;
1384 return ((guint32*)item) + 1;
1388 /* no suitable item found - search lists of larger sizes */
1389 while (++i < NUM_FREE_LISTS) {
1390 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1393 g_assert (item->size > size);
1394 domain->thunk_free_lists [i] = item->next;
1395 return ((guint32*)item) + 1;
1398 /* still nothing found - allocate it */
1400 mono_counters_register ("Generic virtual thunk bytes",
1401 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1404 generic_virtual_thunks_size += size;
1406 p = mono_code_manager_reserve (domain->code_mp, size);
1413 * LOCKING: The domain lock must be held.
1416 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1419 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1421 init_thunk_free_lists (domain);
1423 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1424 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1425 int length = item->length;
1428 /* unlink the first item from the wait list */
1429 domain->thunk_free_lists [0] = item->next;
1430 domain->thunk_free_lists [0]->length = length - 1;
1432 i = list_index_for_size (item->size);
1434 /* put it in the free list */
1435 item->next = domain->thunk_free_lists [i];
1436 domain->thunk_free_lists [i] = item;
1440 if (domain->thunk_free_lists [1]) {
1441 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1442 domain->thunk_free_lists [0]->length++;
1444 g_assert (!domain->thunk_free_lists [0]);
1446 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1447 domain->thunk_free_lists [0]->length = 1;
1451 typedef struct _GenericVirtualCase {
1452 MonoGenericInst *inst;
1455 struct _GenericVirtualCase *next;
1456 } GenericVirtualCase;
1459 * mono_method_add_generic_virtual_invocation:
1461 * @vtable_slot: pointer to the vtable slot
1462 * @method_inst: the method's method_inst
1463 * @code: the method's code
1465 * Registers a call via unmanaged code to a generic virtual method
1466 * instantiation. If the number of calls reaches a threshold
1467 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1468 * virtual method thunk.
1471 mono_method_add_generic_virtual_invocation (MonoDomain *domain, gpointer *vtable_slot,
1472 MonoGenericInst *method_inst, gpointer code)
1474 static gboolean inited = FALSE;
1475 static int num_added = 0;
1477 GenericVirtualCase *gvc, *list;
1478 MonoImtBuilderEntry *entries;
1482 mono_domain_lock (domain);
1483 if (!domain->generic_virtual_cases)
1484 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1486 /* Check whether the case was already added */
1487 gvc = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1489 if (gvc->inst == method_inst)
1494 /* If not found, make a new one */
1496 gvc = mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1497 gvc->inst = method_inst;
1500 gvc->next = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1502 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1505 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1511 if (++gvc->count < THUNK_THRESHOLD) {
1512 mono_domain_unlock (domain);
1517 for (list = gvc; list; list = list->next) {
1518 MonoImtBuilderEntry *entry;
1520 if (list->count < THUNK_THRESHOLD)
1523 entry = g_new0 (MonoImtBuilderEntry, 1);
1524 entry->key = list->inst;
1525 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1527 entry->children = entries->children + 1;
1528 entry->next = entries;
1532 sorted = imt_sort_slot_entries (entries);
1534 if (*vtable_slot != vtable_trampoline)
1535 invalidate_generic_virtual_thunk (domain, *vtable_slot);
1537 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1540 mono_domain_unlock (domain);
1543 MonoImtBuilderEntry *next = entries->next;
1548 for (i = 0; i < sorted->len; ++i)
1549 g_free (g_ptr_array_index (sorted, i));
1550 g_ptr_array_free (sorted, TRUE);
1553 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class);
1556 * mono_class_vtable:
1557 * @domain: the application domain
1558 * @class: the class to initialize
1560 * VTables are domain specific because we create domain specific code, and
1561 * they contain the domain specific static class data.
1562 * On failure, NULL is returned, and class->exception_type is set.
1565 mono_class_vtable (MonoDomain *domain, MonoClass *class)
1567 MonoClassRuntimeInfo *runtime_info;
1571 /* this check can be inlined in jitted code, too */
1572 runtime_info = class->runtime_info;
1573 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1574 return runtime_info->domain_vtables [domain->domain_id];
1575 if (class->exception_type)
1577 return mono_class_create_runtime_vtable (domain, class);
1581 * mono_class_try_get_vtable:
1582 * @domain: the application domain
1583 * @class: the class to initialize
1585 * This function tries to get the associated vtable from @class if
1586 * it was already created.
1589 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *class)
1591 MonoClassRuntimeInfo *runtime_info;
1595 runtime_info = class->runtime_info;
1596 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1597 return runtime_info->domain_vtables [domain->domain_id];
1602 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class)
1605 MonoClassRuntimeInfo *runtime_info, *old_info;
1606 MonoClassField *field;
1609 int imt_table_bytes = 0;
1610 guint32 vtable_size, class_size;
1613 gpointer *interface_offsets;
1615 mono_domain_lock (domain);
1616 runtime_info = class->runtime_info;
1617 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1618 mono_domain_unlock (domain);
1619 return runtime_info->domain_vtables [domain->domain_id];
1621 if (!class->inited || class->exception_type) {
1622 if (!mono_class_init (class) || class->exception_type){
1624 mono_domain_unlock (domain);
1625 exc = mono_class_get_exception_for_failure (class);
1627 mono_raise_exception (exc);
1631 mono_class_init (class);
1634 * For some classes, mono_class_init () already computed class->vtable_size, and
1635 * that is all that is needed because of the vtable trampolines.
1637 if (!class->vtable_size)
1638 mono_class_setup_vtable (class);
1640 if (class->exception_type) {
1641 mono_domain_unlock (domain);
1646 vtable_size = sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
1647 if (class->interface_offsets_count) {
1648 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1649 vtable_size += sizeof (gpointer) * (MONO_IMT_SIZE);
1650 mono_stats.imt_number_of_tables++;
1651 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
1654 vtable_size = sizeof (gpointer) * (class->max_interface_id + 1) +
1655 sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
1658 mono_stats.used_class_count++;
1659 mono_stats.class_vtable_size += vtable_size;
1660 interface_offsets = mono_domain_alloc0 (domain, vtable_size);
1663 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1665 vt = (MonoVTable*) (interface_offsets + class->max_interface_id + 1);
1667 vt->rank = class->rank;
1668 vt->domain = domain;
1670 mono_class_compute_gc_descriptor (class);
1672 * We can't use typed allocation in the non-root domains, since the
1673 * collector needs the GC descriptor stored in the vtable even after
1674 * the mempool containing the vtable is destroyed when the domain is
1675 * unloaded. An alternative might be to allocate vtables in the GC
1676 * heap, but this does not seem to work (it leads to crashes inside
1677 * libgc). If that approach is tried, two gc descriptors need to be
1678 * allocated for each class: one for the root domain, and one for all
1679 * other domains. The second descriptor should contain a bit for the
1680 * vtable field in MonoObject, since we can no longer assume the
1681 * vtable is reachable by other roots after the appdomain is unloaded.
1683 #ifdef HAVE_BOEHM_GC
1684 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1685 vt->gc_descr = GC_NO_DESCRIPTOR;
1688 vt->gc_descr = class->gc_descr;
1690 if ((class_size = mono_class_data_size (class))) {
1691 if (class->has_static_refs) {
1692 gpointer statics_gc_descr;
1694 gsize default_bitmap [4] = {0};
1697 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1698 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
1699 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set? max_set + 1: 0);
1700 vt->data = mono_gc_alloc_fixed (class_size, statics_gc_descr);
1701 mono_domain_add_class_static_data (domain, class, vt->data, NULL);
1702 if (bitmap != default_bitmap)
1705 vt->data = mono_domain_alloc0 (domain, class_size);
1707 mono_stats.class_static_data_size += class_size;
1712 while ((field = mono_class_get_fields (class, &iter))) {
1713 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1715 if (mono_field_is_deleted (field))
1717 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1718 gint32 special_static = class->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (class, field);
1719 if (special_static != SPECIAL_STATIC_NONE) {
1720 guint32 size, offset;
1722 size = mono_type_size (field->type, &align);
1723 offset = mono_alloc_special_static_data (special_static, size, align);
1724 if (!domain->special_static_fields)
1725 domain->special_static_fields = g_hash_table_new (NULL, NULL);
1726 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
1730 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
1731 MonoClass *fklass = mono_class_from_mono_type (field->type);
1732 const char *data = mono_field_get_data (field);
1734 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
1735 t = (char*)vt->data + field->offset;
1736 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
1739 if (fklass->valuetype) {
1740 memcpy (t, data, mono_class_value_size (fklass, NULL));
1742 /* it's a pointer type: add check */
1743 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
1750 vt->max_interface_id = class->max_interface_id;
1751 vt->interface_bitmap = class->interface_bitmap;
1753 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
1754 // class->name, class->interface_offsets_count);
1756 if (! ARCH_USE_IMT) {
1757 /* initialize interface offsets */
1758 for (i = 0; i < class->interface_offsets_count; ++i) {
1759 int interface_id = class->interfaces_packed [i]->interface_id;
1760 int slot = class->interface_offsets_packed [i];
1761 interface_offsets [class->max_interface_id - interface_id] = &(vt->vtable [slot]);
1765 /* FIXME: class_vtable_hash is basically obsolete now: remove as soon
1766 * as we change the code in appdomain.c to invalidate vtables by
1767 * looking at the possible MonoClasses created for the domain.
1769 g_hash_table_insert (domain->class_vtable_hash, class, vt);
1770 /* class->runtime_info is protected by the loader lock, both when
1771 * it it enlarged and when it is stored info.
1773 mono_loader_lock ();
1774 old_info = class->runtime_info;
1775 if (old_info && old_info->max_domain >= domain->domain_id) {
1776 /* someone already created a large enough runtime info */
1777 mono_memory_barrier ();
1778 old_info->domain_vtables [domain->domain_id] = vt;
1780 int new_size = domain->domain_id;
1782 new_size = MAX (new_size, old_info->max_domain);
1784 /* make the new size a power of two */
1786 while (new_size > i)
1789 /* this is a bounded memory retention issue: may want to
1790 * handle it differently when we'll have a rcu-like system.
1792 runtime_info = mono_image_alloc0 (class->image, sizeof (MonoClassRuntimeInfo) + new_size * sizeof (gpointer));
1793 runtime_info->max_domain = new_size - 1;
1794 /* copy the stuff from the older info */
1796 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
1798 runtime_info->domain_vtables [domain->domain_id] = vt;
1800 mono_memory_barrier ();
1801 class->runtime_info = runtime_info;
1803 mono_loader_unlock ();
1805 /* Initialize vtable */
1806 if (vtable_trampoline) {
1807 // This also covers the AOT case
1808 for (i = 0; i < class->vtable_size; ++i) {
1809 vt->vtable [i] = vtable_trampoline;
1812 mono_class_setup_vtable (class);
1814 for (i = 0; i < class->vtable_size; ++i) {
1817 if ((cm = class->vtable [i])) {
1818 if (mono_method_signature (cm)->generic_param_count)
1819 /* FIXME: Why is this needed ? */
1820 vt->vtable [i] = cm;
1822 vt->vtable [i] = vtable_trampoline? vtable_trampoline: arch_create_jit_trampoline (cm);
1827 if (ARCH_USE_IMT && imt_table_bytes) {
1828 /* Now that the vtable is full, we can actually fill up the IMT */
1829 if (imt_trampoline) {
1830 /* lazy construction of the IMT entries enabled */
1831 for (i = 0; i < MONO_IMT_SIZE; ++i)
1832 interface_offsets [i] = imt_trampoline;
1834 build_imt (class, vt, domain, interface_offsets, NULL);
1838 mono_domain_unlock (domain);
1840 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
1841 if (mono_is_security_manager_active () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND)) {
1842 MonoException *exc = mono_class_get_exception_for_failure (class);
1844 mono_raise_exception (exc);
1847 /* make sure the parent is initialized */
1849 mono_class_vtable (domain, class->parent);
1851 vt->type = mono_type_get_object (domain, &class->byval_arg);
1852 if (class->contextbound)
1861 * mono_class_proxy_vtable:
1862 * @domain: the application domain
1863 * @remove_class: the remote class
1865 * Creates a vtable for transparent proxies. It is basically
1866 * a copy of the real vtable of the class wrapped in @remote_class,
1867 * but all function pointers invoke the remoting functions, and
1868 * vtable->klass points to the transparent proxy class, and not to @class.
1871 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
1873 MonoVTable *vt, *pvt;
1874 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
1876 GSList *extra_interfaces = NULL;
1877 MonoClass *class = remote_class->proxy_class;
1878 gpointer *interface_offsets;
1880 vt = mono_class_vtable (domain, class);
1881 max_interface_id = vt->max_interface_id;
1883 /* Calculate vtable space for extra interfaces */
1884 for (j = 0; j < remote_class->interface_count; j++) {
1885 MonoClass* iclass = remote_class->interfaces[j];
1889 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
1890 continue; /* interface implemented by the class */
1891 if (g_slist_find (extra_interfaces, iclass))
1894 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
1896 method_count = mono_class_num_methods (iclass);
1898 ifaces = mono_class_get_implemented_interfaces (iclass);
1900 for (i = 0; i < ifaces->len; ++i) {
1901 MonoClass *ic = g_ptr_array_index (ifaces, i);
1902 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
1903 continue; /* interface implemented by the class */
1904 if (g_slist_find (extra_interfaces, ic))
1906 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
1907 method_count += mono_class_num_methods (ic);
1909 g_ptr_array_free (ifaces, TRUE);
1912 extra_interface_vtsize += method_count * sizeof (gpointer);
1913 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
1917 mono_stats.imt_number_of_tables++;
1918 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
1919 vtsize = sizeof (gpointer) * (MONO_IMT_SIZE) +
1920 sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
1922 vtsize = sizeof (gpointer) * (max_interface_id + 1) +
1923 sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
1926 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
1928 interface_offsets = mono_domain_alloc0 (domain, vtsize + extra_interface_vtsize);
1930 pvt = (MonoVTable*) (interface_offsets + MONO_IMT_SIZE);
1932 pvt = (MonoVTable*) (interface_offsets + max_interface_id + 1);
1933 memcpy (pvt, vt, sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer));
1935 pvt->klass = mono_defaults.transparent_proxy_class;
1936 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
1937 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
1939 /* initialize vtable */
1940 mono_class_setup_vtable (class);
1941 for (i = 0; i < class->vtable_size; ++i) {
1944 if ((cm = class->vtable [i]))
1945 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
1947 pvt->vtable [i] = NULL;
1950 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
1951 /* create trampolines for abstract methods */
1952 for (k = class; k; k = k->parent) {
1954 gpointer iter = NULL;
1955 while ((m = mono_class_get_methods (k, &iter)))
1956 if (!pvt->vtable [m->slot])
1957 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
1961 pvt->max_interface_id = max_interface_id;
1962 pvt->interface_bitmap = mono_domain_alloc0 (domain, sizeof (guint8) * (max_interface_id/8 + 1 ));
1964 if (! ARCH_USE_IMT) {
1965 /* initialize interface offsets */
1966 for (i = 0; i < class->interface_offsets_count; ++i) {
1967 int interface_id = class->interfaces_packed [i]->interface_id;
1968 int slot = class->interface_offsets_packed [i];
1969 interface_offsets [class->max_interface_id - interface_id] = &(pvt->vtable [slot]);
1972 for (i = 0; i < class->interface_offsets_count; ++i) {
1973 int interface_id = class->interfaces_packed [i]->interface_id;
1974 pvt->interface_bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
1977 if (extra_interfaces) {
1978 int slot = class->vtable_size;
1984 /* Create trampolines for the methods of the interfaces */
1985 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1986 interf = list_item->data;
1988 if (! ARCH_USE_IMT) {
1989 interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
1991 pvt->interface_bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
1995 while ((cm = mono_class_get_methods (interf, &iter)))
1996 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
1998 slot += mono_class_num_methods (interf);
2000 if (! ARCH_USE_IMT) {
2001 g_slist_free (extra_interfaces);
2006 /* Now that the vtable is full, we can actually fill up the IMT */
2007 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
2008 if (extra_interfaces) {
2009 g_slist_free (extra_interfaces);
2017 * mono_class_field_is_special_static:
2019 * Returns whether @field is a thread/context static field.
2022 mono_class_field_is_special_static (MonoClassField *field)
2024 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2026 if (mono_field_is_deleted (field))
2028 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2029 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2036 * mono_class_has_special_static_fields:
2038 * Returns whenever @klass has any thread/context static fields.
2041 mono_class_has_special_static_fields (MonoClass *klass)
2043 MonoClassField *field;
2047 while ((field = mono_class_get_fields (klass, &iter))) {
2048 g_assert (field->parent == klass);
2049 if (mono_class_field_is_special_static (field))
2057 * create_remote_class_key:
2058 * Creates an array of pointers that can be used as a hash key for a remote class.
2059 * The first element of the array is the number of pointers.
2062 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2067 if (remote_class == NULL) {
2068 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2069 key = g_malloc (sizeof(gpointer) * 3);
2070 key [0] = GINT_TO_POINTER (2);
2071 key [1] = mono_defaults.marshalbyrefobject_class;
2072 key [2] = extra_class;
2074 key = g_malloc (sizeof(gpointer) * 2);
2075 key [0] = GINT_TO_POINTER (1);
2076 key [1] = extra_class;
2079 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2080 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2081 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2082 key [1] = remote_class->proxy_class;
2084 // Keep the list of interfaces sorted
2085 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2086 if (extra_class && remote_class->interfaces [i] > extra_class) {
2087 key [j++] = extra_class;
2090 key [j] = remote_class->interfaces [i];
2093 key [j] = extra_class;
2095 // Replace the old class. The interface list is the same
2096 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2097 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2098 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2099 for (i = 0; i < remote_class->interface_count; i++)
2100 key [2 + i] = remote_class->interfaces [i];
2108 * copy_remote_class_key:
2110 * Make a copy of KEY in the domain and return the copy.
2113 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2115 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2116 gpointer *mp_key = mono_domain_alloc (domain, key_size);
2118 memcpy (mp_key, key, key_size);
2124 * mono_remote_class:
2125 * @domain: the application domain
2126 * @class_name: name of the remote class
2128 * Creates and initializes a MonoRemoteClass object for a remote type.
2132 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2134 MonoRemoteClass *rc;
2135 gpointer* key, *mp_key;
2137 key = create_remote_class_key (NULL, proxy_class);
2139 mono_domain_lock (domain);
2140 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2144 mono_domain_unlock (domain);
2148 mp_key = copy_remote_class_key (domain, key);
2152 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2153 rc = mono_domain_alloc (domain, sizeof(MonoRemoteClass) + sizeof(MonoClass*));
2154 rc->interface_count = 1;
2155 rc->interfaces [0] = proxy_class;
2156 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2158 rc = mono_domain_alloc (domain, sizeof(MonoRemoteClass));
2159 rc->interface_count = 0;
2160 rc->proxy_class = proxy_class;
2163 rc->default_vtable = NULL;
2164 rc->xdomain_vtable = NULL;
2165 rc->proxy_class_name = mono_string_to_utf8_mp (domain->mp, class_name);
2166 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2168 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2170 mono_domain_unlock (domain);
2175 * clone_remote_class:
2176 * Creates a copy of the remote_class, adding the provided class or interface
2178 static MonoRemoteClass*
2179 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2181 MonoRemoteClass *rc;
2182 gpointer* key, *mp_key;
2184 key = create_remote_class_key (remote_class, extra_class);
2185 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2191 mp_key = copy_remote_class_key (domain, key);
2195 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2197 rc = mono_domain_alloc (domain, sizeof(MonoRemoteClass) + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2198 rc->proxy_class = remote_class->proxy_class;
2199 rc->interface_count = remote_class->interface_count + 1;
2201 // Keep the list of interfaces sorted, since the hash key of
2202 // the remote class depends on this
2203 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2204 if (remote_class->interfaces [i] > extra_class && i == j)
2205 rc->interfaces [j++] = extra_class;
2206 rc->interfaces [j] = remote_class->interfaces [i];
2209 rc->interfaces [j] = extra_class;
2211 // Replace the old class. The interface array is the same
2212 rc = mono_domain_alloc (domain, sizeof(MonoRemoteClass) + sizeof(MonoClass*) * remote_class->interface_count);
2213 rc->proxy_class = extra_class;
2214 rc->interface_count = remote_class->interface_count;
2215 if (rc->interface_count > 0)
2216 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2219 rc->default_vtable = NULL;
2220 rc->xdomain_vtable = NULL;
2221 rc->proxy_class_name = remote_class->proxy_class_name;
2223 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2229 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2231 mono_domain_lock (domain);
2232 if (rp->target_domain_id != -1) {
2233 if (remote_class->xdomain_vtable == NULL)
2234 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2235 mono_domain_unlock (domain);
2236 return remote_class->xdomain_vtable;
2238 if (remote_class->default_vtable == NULL) {
2241 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2242 klass = mono_class_from_mono_type (type);
2243 if ((klass->is_com_object || (mono_defaults.com_object_class && klass == mono_defaults.com_object_class)) && !mono_class_vtable (mono_domain_get (), klass)->remote)
2244 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2246 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2249 mono_domain_unlock (domain);
2250 return remote_class->default_vtable;
2254 * mono_upgrade_remote_class:
2255 * @domain: the application domain
2256 * @tproxy: the proxy whose remote class has to be upgraded.
2257 * @klass: class to which the remote class can be casted.
2259 * Updates the vtable of the remote class by adding the necessary method slots
2260 * and interface offsets so it can be safely casted to klass. klass can be a
2261 * class or an interface.
2264 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2266 MonoTransparentProxy *tproxy;
2267 MonoRemoteClass *remote_class;
2268 gboolean redo_vtable;
2270 mono_domain_lock (domain);
2272 tproxy = (MonoTransparentProxy*) proxy_object;
2273 remote_class = tproxy->remote_class;
2275 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2278 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2279 if (remote_class->interfaces [i] == klass)
2280 redo_vtable = FALSE;
2283 redo_vtable = (remote_class->proxy_class != klass);
2287 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2288 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2291 mono_domain_unlock (domain);
2296 * mono_object_get_virtual_method:
2297 * @obj: object to operate on.
2300 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2301 * the instance of a callvirt of method.
2304 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2307 MonoMethod **vtable;
2309 MonoMethod *res = NULL;
2311 klass = mono_object_class (obj);
2312 if (klass == mono_defaults.transparent_proxy_class) {
2313 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2319 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2322 mono_class_setup_vtable (klass);
2323 vtable = klass->vtable;
2325 if (method->slot == -1) {
2326 /* method->slot might not be set for instances of generic methods */
2327 if (method->is_inflated) {
2328 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2329 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2332 g_assert_not_reached ();
2336 /* check method->slot is a valid index: perform isinstance? */
2337 if (method->slot != -1) {
2338 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2340 res = vtable [mono_class_interface_offset (klass, method->klass) + method->slot];
2342 res = vtable [method->slot];
2347 /* It may be an interface, abstract class method or generic method */
2348 if (!res || mono_method_signature (res)->generic_param_count)
2351 /* generic methods demand invoke_with_check */
2352 if (mono_method_signature (res)->generic_param_count)
2353 res = mono_marshal_get_remoting_invoke_with_check (res);
2355 res = mono_marshal_get_remoting_invoke (res);
2357 if (method->is_inflated) {
2358 /* Have to inflate the result */
2359 res = mono_class_inflate_generic_method (res, &((MonoMethodInflated*)method)->context);
2369 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2371 g_error ("runtime invoke called on uninitialized runtime");
2375 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2378 * mono_runtime_invoke:
2379 * @method: method to invoke
2380 * @obJ: object instance
2381 * @params: arguments to the method
2382 * @exc: exception information.
2384 * Invokes the method represented by @method on the object @obj.
2386 * obj is the 'this' pointer, it should be NULL for static
2387 * methods, a MonoObject* for object instances and a pointer to
2388 * the value type for value types.
2390 * The params array contains the arguments to the method with the
2391 * same convention: MonoObject* pointers for object instances and
2392 * pointers to the value type otherwise.
2394 * From unmanaged code you'll usually use the
2395 * mono_runtime_invoke() variant.
2397 * Note that this function doesn't handle virtual methods for
2398 * you, it will exec the exact method you pass: we still need to
2399 * expose a function to lookup the derived class implementation
2400 * of a virtual method (there are examples of this in the code,
2403 * You can pass NULL as the exc argument if you don't want to
2404 * catch exceptions, otherwise, *exc will be set to the exception
2405 * thrown, if any. if an exception is thrown, you can't use the
2406 * MonoObject* result from the function.
2408 * If the method returns a value type, it is boxed in an object
2412 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2414 if (mono_runtime_get_no_exec ())
2415 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2417 return default_mono_runtime_invoke (method, obj, params, exc);
2421 * mono_method_get_unmanaged_thunk:
2422 * @method: method to generate a thunk for.
2424 * Returns an unmanaged->managed thunk that can be used to call
2425 * a managed method directly from C.
2427 * The thunk's C signature closely matches the managed signature:
2429 * C#: public bool Equals (object obj);
2430 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2431 * MonoObject*, MonoException**);
2433 * The 1st ("this") parameter must not be used with static methods:
2435 * C#: public static bool ReferenceEquals (object a, object b);
2436 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2439 * The last argument must be a non-null pointer of a MonoException* pointer.
2440 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2441 * exception has been thrown in managed code. Otherwise it will point
2442 * to the MonoException* caught by the thunk. In this case, the result of
2443 * the thunk is undefined:
2445 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2446 * MonoException *ex = NULL;
2447 * Equals func = mono_method_get_unmanaged_thunk (method);
2448 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2450 * // handle exception
2453 * The calling convention of the thunk matches the platform's default
2454 * convention. This means that under Windows, C declarations must
2455 * contain the __stdcall attribute:
2457 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2458 * MonoObject*, MonoException**);
2462 * Value type arguments and return values are treated as they were objects:
2464 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2465 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2467 * Arguments must be properly boxed upon trunk's invocation, while return
2468 * values must be unboxed.
2471 mono_method_get_unmanaged_thunk (MonoMethod *method)
2473 method = mono_marshal_get_thunk_invoke_wrapper (method);
2474 return mono_compile_method (method);
2478 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
2482 gpointer *p = (gpointer*)dest;
2489 case MONO_TYPE_BOOLEAN:
2491 case MONO_TYPE_U1: {
2492 guint8 *p = (guint8*)dest;
2493 *p = value ? *(guint8*)value : 0;
2498 case MONO_TYPE_CHAR: {
2499 guint16 *p = (guint16*)dest;
2500 *p = value ? *(guint16*)value : 0;
2503 #if SIZEOF_VOID_P == 4
2508 case MONO_TYPE_U4: {
2509 gint32 *p = (gint32*)dest;
2510 *p = value ? *(gint32*)value : 0;
2513 #if SIZEOF_VOID_P == 8
2518 case MONO_TYPE_U8: {
2519 gint64 *p = (gint64*)dest;
2520 *p = value ? *(gint64*)value : 0;
2523 case MONO_TYPE_R4: {
2524 float *p = (float*)dest;
2525 *p = value ? *(float*)value : 0;
2528 case MONO_TYPE_R8: {
2529 double *p = (double*)dest;
2530 *p = value ? *(double*)value : 0;
2533 case MONO_TYPE_STRING:
2534 case MONO_TYPE_SZARRAY:
2535 case MONO_TYPE_CLASS:
2536 case MONO_TYPE_OBJECT:
2537 case MONO_TYPE_ARRAY:
2538 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2540 case MONO_TYPE_FNPTR:
2541 case MONO_TYPE_PTR: {
2542 gpointer *p = (gpointer*)dest;
2543 *p = deref_pointer? *(gpointer*)value: value;
2546 case MONO_TYPE_VALUETYPE:
2547 /* note that 't' and 'type->type' can be different */
2548 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
2549 t = mono_class_enum_basetype (type->data.klass)->type;
2553 size = mono_class_value_size (mono_class_from_mono_type (type), NULL);
2555 memset (dest, 0, size);
2557 memcpy (dest, value, size);
2560 case MONO_TYPE_GENERICINST:
2561 t = type->data.generic_class->container_class->byval_arg.type;
2564 g_warning ("got type %x", type->type);
2565 g_assert_not_reached ();
2570 * mono_field_set_value:
2571 * @obj: Instance object
2572 * @field: MonoClassField describing the field to set
2573 * @value: The value to be set
2575 * Sets the value of the field described by @field in the object instance @obj
2576 * to the value passed in @value. This method should only be used for instance
2577 * fields. For static fields, use mono_field_static_set_value.
2579 * The value must be on the native format of the field type.
2582 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
2586 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2588 dest = (char*)obj + field->offset;
2589 set_value (field->type, dest, value, FALSE);
2593 * mono_field_static_set_value:
2594 * @field: MonoClassField describing the field to set
2595 * @value: The value to be set
2597 * Sets the value of the static field described by @field
2598 * to the value passed in @value.
2600 * The value must be on the native format of the field type.
2603 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
2607 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2608 /* you cant set a constant! */
2609 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
2611 dest = (char*)vt->data + field->offset;
2612 set_value (field->type, dest, value, FALSE);
2615 /* Used by the debugger */
2617 mono_vtable_get_static_field_data (MonoVTable *vt)
2623 * mono_field_get_value:
2624 * @obj: Object instance
2625 * @field: MonoClassField describing the field to fetch information from
2626 * @value: pointer to the location where the value will be stored
2628 * Use this routine to get the value of the field @field in the object
2631 * The pointer provided by value must be of the field type, for reference
2632 * types this is a MonoObject*, for value types its the actual pointer to
2637 * mono_field_get_value (obj, int_field, &i);
2640 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
2644 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2646 src = (char*)obj + field->offset;
2647 set_value (field->type, value, src, TRUE);
2651 * mono_field_get_value_object:
2652 * @domain: domain where the object will be created (if boxing)
2653 * @field: MonoClassField describing the field to fetch information from
2654 * @obj: The object instance for the field.
2656 * Returns: a new MonoObject with the value from the given field. If the
2657 * field represents a value type, the value is boxed.
2661 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
2665 MonoVTable *vtable = NULL;
2667 gboolean is_static = FALSE;
2668 gboolean is_ref = FALSE;
2670 switch (field->type->type) {
2671 case MONO_TYPE_STRING:
2672 case MONO_TYPE_OBJECT:
2673 case MONO_TYPE_CLASS:
2674 case MONO_TYPE_ARRAY:
2675 case MONO_TYPE_SZARRAY:
2680 case MONO_TYPE_BOOLEAN:
2683 case MONO_TYPE_CHAR:
2692 case MONO_TYPE_VALUETYPE:
2693 is_ref = field->type->byref;
2695 case MONO_TYPE_GENERICINST:
2696 is_ref = !field->type->data.generic_class->container_class->valuetype;
2699 g_error ("type 0x%x not handled in "
2700 "mono_field_get_value_object", field->type->type);
2704 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
2706 vtable = mono_class_vtable (domain, field->parent);
2707 if (!vtable->initialized)
2708 mono_runtime_class_init (vtable);
2713 mono_field_static_get_value (vtable, field, &o);
2715 mono_field_get_value (obj, field, &o);
2720 /* boxed value type */
2721 klass = mono_class_from_mono_type (field->type);
2722 o = mono_object_new (domain, klass);
2723 v = ((gchar *) o) + sizeof (MonoObject);
2725 mono_field_static_get_value (vtable, field, v);
2727 mono_field_get_value (obj, field, v);
2734 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
2737 const char *p = blob;
2738 mono_metadata_decode_blob_size (p, &p);
2741 case MONO_TYPE_BOOLEAN:
2744 *(guint8 *) value = *p;
2746 case MONO_TYPE_CHAR:
2749 *(guint16*) value = read16 (p);
2753 *(guint32*) value = read32 (p);
2757 *(guint64*) value = read64 (p);
2760 readr4 (p, (float*) value);
2763 readr8 (p, (double*) value);
2765 case MONO_TYPE_STRING:
2766 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
2768 case MONO_TYPE_CLASS:
2769 *(gpointer*) value = NULL;
2773 g_warning ("type 0x%02x should not be in constant table", type);
2779 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
2781 MonoTypeEnum def_type;
2784 data = mono_class_get_field_default_value (field, &def_type);
2785 mono_get_constant_value_from_blob (domain, def_type, data, value);
2789 * mono_field_static_get_value:
2790 * @vt: vtable to the object
2791 * @field: MonoClassField describing the field to fetch information from
2792 * @value: where the value is returned
2794 * Use this routine to get the value of the static field @field value.
2796 * The pointer provided by value must be of the field type, for reference
2797 * types this is a MonoObject*, for value types its the actual pointer to
2802 * mono_field_static_get_value (vt, int_field, &i);
2805 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
2809 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2811 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
2812 get_default_field_value (vt->domain, field, value);
2816 src = (char*)vt->data + field->offset;
2817 set_value (field->type, value, src, TRUE);
2821 * mono_property_set_value:
2822 * @prop: MonoProperty to set
2823 * @obj: instance object on which to act
2824 * @params: parameters to pass to the propery
2825 * @exc: optional exception
2827 * Invokes the property's set method with the given arguments on the
2828 * object instance obj (or NULL for static properties).
2830 * You can pass NULL as the exc argument if you don't want to
2831 * catch exceptions, otherwise, *exc will be set to the exception
2832 * thrown, if any. if an exception is thrown, you can't use the
2833 * MonoObject* result from the function.
2836 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
2838 default_mono_runtime_invoke (prop->set, obj, params, exc);
2842 * mono_property_get_value:
2843 * @prop: MonoProperty to fetch
2844 * @obj: instance object on which to act
2845 * @params: parameters to pass to the propery
2846 * @exc: optional exception
2848 * Invokes the property's get method with the given arguments on the
2849 * object instance obj (or NULL for static properties).
2851 * You can pass NULL as the exc argument if you don't want to
2852 * catch exceptions, otherwise, *exc will be set to the exception
2853 * thrown, if any. if an exception is thrown, you can't use the
2854 * MonoObject* result from the function.
2856 * Returns: the value from invoking the get method on the property.
2859 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
2861 return default_mono_runtime_invoke (prop->get, obj, params, exc);
2865 * mono_nullable_init:
2866 * @buf: The nullable structure to initialize.
2867 * @value: the value to initialize from
2868 * @klass: the type for the object
2870 * Initialize the nullable structure pointed to by @buf from @value which
2871 * should be a boxed value type. The size of @buf should be able to hold
2872 * as much data as the @klass->instance_size (which is the number of bytes
2873 * that will be copies).
2875 * Since Nullables have variable structure, we can not define a C
2876 * structure for them.
2879 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
2881 MonoClass *param_class = klass->cast_class;
2883 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
2884 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
2886 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
2888 memcpy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
2890 memset (buf + klass->fields [0].offset - sizeof (MonoObject), 0, mono_class_value_size (param_class, NULL));
2894 * mono_nullable_box:
2895 * @buf: The buffer representing the data to be boxed
2896 * @klass: the type to box it as.
2898 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
2902 mono_nullable_box (guint8 *buf, MonoClass *klass)
2904 MonoClass *param_class = klass->cast_class;
2906 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
2907 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
2909 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
2910 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
2911 memcpy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
2919 * mono_get_delegate_invoke:
2920 * @klass: The delegate class
2922 * Returns: the MonoMethod for the "Invoke" method in the delegate klass
2925 mono_get_delegate_invoke (MonoClass *klass)
2929 im = mono_class_get_method_from_name (klass, "Invoke", -1);
2936 * mono_runtime_delegate_invoke:
2937 * @delegate: pointer to a delegate object.
2938 * @params: parameters for the delegate.
2939 * @exc: Pointer to the exception result.
2941 * Invokes the delegate method @delegate with the parameters provided.
2943 * You can pass NULL as the exc argument if you don't want to
2944 * catch exceptions, otherwise, *exc will be set to the exception
2945 * thrown, if any. if an exception is thrown, you can't use the
2946 * MonoObject* result from the function.
2949 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
2953 im = mono_get_delegate_invoke (delegate->vtable->klass);
2956 return mono_runtime_invoke (im, delegate, params, exc);
2959 static char **main_args = NULL;
2960 static int num_main_args;
2963 * mono_runtime_get_main_args:
2965 * Returns: a MonoArray with the arguments passed to the main program
2968 mono_runtime_get_main_args (void)
2972 MonoDomain *domain = mono_domain_get ();
2977 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
2979 for (i = 0; i < num_main_args; ++i)
2980 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
2986 fire_process_exit_event (void)
2988 MonoClassField *field;
2989 MonoDomain *domain = mono_domain_get ();
2991 MonoObject *delegate, *exc;
2993 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "ProcessExit");
2996 if (domain != mono_get_root_domain ())
2999 delegate = *(MonoObject **)(((char *)domain->domain) + field->offset);
3000 if (delegate == NULL)
3005 mono_runtime_delegate_invoke (delegate, pa, &exc);
3009 * mono_runtime_run_main:
3010 * @method: the method to start the application with (usually Main)
3011 * @argc: number of arguments from the command line
3012 * @argv: array of strings from the command line
3013 * @exc: excetption results
3015 * Execute a standard Main() method (argc/argv contains the
3016 * executable name). This method also sets the command line argument value
3017 * needed by System.Environment.
3022 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3026 MonoArray *args = NULL;
3027 MonoDomain *domain = mono_domain_get ();
3028 gchar *utf8_fullpath;
3031 g_assert (method != NULL);
3033 mono_thread_set_main (mono_thread_current ());
3035 main_args = g_new0 (char*, argc);
3036 num_main_args = argc;
3038 if (!g_path_is_absolute (argv [0])) {
3039 gchar *basename = g_path_get_basename (argv [0]);
3040 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3044 utf8_fullpath = mono_utf8_from_external (fullpath);
3045 if(utf8_fullpath == NULL) {
3046 /* Printing the arg text will cause glib to
3047 * whinge about "Invalid UTF-8", but at least
3048 * its relevant, and shows the problem text
3051 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3052 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3059 utf8_fullpath = mono_utf8_from_external (argv[0]);
3060 if(utf8_fullpath == NULL) {
3061 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3062 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3067 main_args [0] = utf8_fullpath;
3069 for (i = 1; i < argc; ++i) {
3072 utf8_arg=mono_utf8_from_external (argv[i]);
3073 if(utf8_arg==NULL) {
3074 /* Ditto the comment about Invalid UTF-8 here */
3075 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3076 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3080 main_args [i] = utf8_arg;
3084 if (mono_method_signature (method)->param_count) {
3085 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3086 for (i = 0; i < argc; ++i) {
3087 /* The encodings should all work, given that
3088 * we've checked all these args for the
3091 gchar *str = mono_utf8_from_external (argv [i]);
3092 MonoString *arg = mono_string_new (domain, str);
3093 mono_array_setref (args, i, arg);
3097 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3100 mono_assembly_set_main (method->klass->image->assembly);
3102 result = mono_runtime_exec_main (method, args, exc);
3103 fire_process_exit_event ();
3107 /* Used in call_unhandled_exception_delegate */
3109 create_unhandled_exception_eventargs (MonoObject *exc)
3113 MonoMethod *method = NULL;
3114 MonoBoolean is_terminating = TRUE;
3117 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
3120 mono_class_init (klass);
3122 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
3123 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
3127 args [1] = &is_terminating;
3129 obj = mono_object_new (mono_domain_get (), klass);
3130 mono_runtime_invoke (method, obj, args, NULL);
3135 /* Used in mono_unhandled_exception */
3137 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
3138 MonoObject *e = NULL;
3141 pa [0] = domain->domain;
3142 pa [1] = create_unhandled_exception_eventargs (exc);
3143 mono_runtime_delegate_invoke (delegate, pa, &e);
3146 gchar *msg = mono_string_to_utf8 (((MonoException *) e)->message);
3147 g_warning ("exception inside UnhandledException handler: %s\n", msg);
3152 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
3155 * mono_runtime_unhandled_exception_policy_set:
3156 * @policy: the new policy
3158 * This is a VM internal routine.
3160 * Sets the runtime policy for handling unhandled exceptions.
3163 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
3164 runtime_unhandled_exception_policy = policy;
3168 * mono_runtime_unhandled_exception_policy_get:
3170 * This is a VM internal routine.
3172 * Gets the runtime policy for handling unhandled exceptions.
3174 MonoRuntimeUnhandledExceptionPolicy
3175 mono_runtime_unhandled_exception_policy_get (void) {
3176 return runtime_unhandled_exception_policy;
3180 * mono_unhandled_exception:
3181 * @exc: exception thrown
3183 * This is a VM internal routine.
3185 * We call this function when we detect an unhandled exception
3186 * in the default domain.
3188 * It invokes the * UnhandledException event in AppDomain or prints
3189 * a warning to the console
3192 mono_unhandled_exception (MonoObject *exc)
3194 MonoDomain *current_domain = mono_domain_get ();
3195 MonoDomain *root_domain = mono_get_root_domain ();
3196 MonoClassField *field;
3197 MonoObject *current_appdomain_delegate;
3198 MonoObject *root_appdomain_delegate;
3200 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
3201 "UnhandledException");
3204 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
3205 gboolean abort_process = (mono_thread_current () == main_thread) ||
3206 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT);
3207 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
3208 if (current_domain != root_domain && (mono_framework_version () >= 2)) {
3209 current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
3211 current_appdomain_delegate = NULL;
3214 /* set exitcode only if we will abort the process */
3216 mono_environment_exitcode_set (1);
3217 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
3218 mono_print_unhandled_exception (exc);
3220 if (root_appdomain_delegate) {
3221 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
3223 if (current_appdomain_delegate) {
3224 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
3231 * Launch a new thread to execute a function
3233 * main_func is called back from the thread with main_args as the
3234 * parameter. The callback function is expected to start Main()
3235 * eventually. This function then waits for all managed threads to
3237 * It is not necesseray anymore to execute managed code in a subthread,
3238 * so this function should not be used anymore by default: just
3239 * execute the code and then call mono_thread_manage ().
3242 mono_runtime_exec_managed_code (MonoDomain *domain,
3243 MonoMainThreadFunc main_func,
3246 mono_thread_create (domain, main_func, main_args);
3248 mono_thread_manage ();
3252 * Execute a standard Main() method (args doesn't contain the
3256 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
3261 MonoCustomAttrInfo* cinfo;
3262 gboolean has_stathread_attribute;
3263 MonoThread* thread = mono_thread_current ();
3269 domain = mono_object_domain (args);
3270 if (!domain->entry_assembly) {
3272 MonoAssembly *assembly;
3274 assembly = method->klass->image->assembly;
3275 domain->entry_assembly = assembly;
3276 /* Domains created from another domain already have application_base and configuration_file set */
3277 if (domain->setup->application_base == NULL) {
3278 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
3281 if (domain->setup->configuration_file == NULL) {
3282 str = g_strconcat (assembly->image->name, ".config", NULL);
3283 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
3285 mono_set_private_bin_path_from_config (domain);
3289 cinfo = mono_custom_attrs_from_method (method);
3291 static MonoClass *stathread_attribute = NULL;
3292 if (!stathread_attribute)
3293 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
3294 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
3296 mono_custom_attrs_free (cinfo);
3298 has_stathread_attribute = FALSE;
3300 if (has_stathread_attribute) {
3301 thread->apartment_state = ThreadApartmentState_STA;
3302 } else if (mono_framework_version () == 1) {
3303 thread->apartment_state = ThreadApartmentState_Unknown;
3305 thread->apartment_state = ThreadApartmentState_MTA;
3307 mono_thread_init_apartment_state ();
3309 mono_debugger_event (MONO_DEBUGGER_EVENT_REACHED_MAIN, 0, 0);
3311 /* FIXME: check signature of method */
3312 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
3314 res = mono_runtime_invoke (method, NULL, pa, exc);
3316 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
3320 mono_environment_exitcode_set (rval);
3322 mono_runtime_invoke (method, NULL, pa, exc);
3326 /* If the return type of Main is void, only
3327 * set the exitcode if an exception was thrown
3328 * (we don't want to blow away an
3329 * explicitly-set exit code)
3332 mono_environment_exitcode_set (rval);
3336 mono_debugger_event (MONO_DEBUGGER_EVENT_MAIN_EXITED, (guint64) (gsize) rval, 0);
3342 * mono_install_runtime_invoke:
3343 * @func: Function to install
3345 * This is a VM internal routine
3348 mono_install_runtime_invoke (MonoInvokeFunc func)
3350 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
3355 * mono_runtime_invoke_array:
3356 * @method: method to invoke
3357 * @obJ: object instance
3358 * @params: arguments to the method
3359 * @exc: exception information.
3361 * Invokes the method represented by @method on the object @obj.
3363 * obj is the 'this' pointer, it should be NULL for static
3364 * methods, a MonoObject* for object instances and a pointer to
3365 * the value type for value types.
3367 * The params array contains the arguments to the method with the
3368 * same convention: MonoObject* pointers for object instances and
3369 * pointers to the value type otherwise. The _invoke_array
3370 * variant takes a C# object[] as the params argument (MonoArray
3371 * *params): in this case the value types are boxed inside the
3372 * respective reference representation.
3374 * From unmanaged code you'll usually use the
3375 * mono_runtime_invoke() variant.
3377 * Note that this function doesn't handle virtual methods for
3378 * you, it will exec the exact method you pass: we still need to
3379 * expose a function to lookup the derived class implementation
3380 * of a virtual method (there are examples of this in the code,
3383 * You can pass NULL as the exc argument if you don't want to
3384 * catch exceptions, otherwise, *exc will be set to the exception
3385 * thrown, if any. if an exception is thrown, you can't use the
3386 * MonoObject* result from the function.
3388 * If the method returns a value type, it is boxed in an object
3392 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
3395 MonoMethodSignature *sig = mono_method_signature (method);
3396 gpointer *pa = NULL;
3399 gboolean has_byref_nullables = FALSE;
3401 if (NULL != params) {
3402 pa = alloca (sizeof (gpointer) * mono_array_length (params));
3403 for (i = 0; i < mono_array_length (params); i++) {
3404 MonoType *t = sig->params [i];
3410 case MONO_TYPE_BOOLEAN:
3413 case MONO_TYPE_CHAR:
3422 case MONO_TYPE_VALUETYPE:
3423 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
3424 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
3425 pa [i] = mono_array_get (params, MonoObject*, i);
3427 has_byref_nullables = TRUE;
3429 /* MS seems to create the objects if a null is passed in */
3430 if (!mono_array_get (params, MonoObject*, i))
3431 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
3435 * We can't pass the unboxed vtype byref to the callee, since
3436 * that would mean the callee would be able to modify boxed
3437 * primitive types. So we (and MS) make a copy of the boxed
3438 * object, pass that to the callee, and replace the original
3439 * boxed object in the arg array with the copy.
3441 MonoObject *orig = mono_array_get (params, MonoObject*, i);
3442 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
3443 mono_array_setref (params, i, copy);
3446 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
3449 case MONO_TYPE_STRING:
3450 case MONO_TYPE_OBJECT:
3451 case MONO_TYPE_CLASS:
3452 case MONO_TYPE_ARRAY:
3453 case MONO_TYPE_SZARRAY:
3455 pa [i] = mono_array_addr (params, MonoObject*, i);
3456 // FIXME: I need to check this code path
3458 pa [i] = mono_array_get (params, MonoObject*, i);
3460 case MONO_TYPE_GENERICINST:
3462 t = &t->data.generic_class->container_class->this_arg;
3464 t = &t->data.generic_class->container_class->byval_arg;
3467 g_error ("type 0x%x not handled in ves_icall_InternalInvoke", sig->params [i]->type);
3472 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
3475 if (mono_class_is_nullable (method->klass)) {
3476 /* Need to create a boxed vtype instead */
3482 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
3486 obj = mono_object_new (mono_domain_get (), method->klass);
3487 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
3488 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
3490 if (method->klass->valuetype)
3491 o = mono_object_unbox (obj);
3494 } else if (method->klass->valuetype) {
3495 obj = mono_value_box (mono_domain_get (), method->klass, obj);
3498 mono_runtime_invoke (method, o, pa, exc);
3501 if (mono_class_is_nullable (method->klass)) {
3502 MonoObject *nullable;
3504 /* Convert the unboxed vtype into a Nullable structure */
3505 nullable = mono_object_new (mono_domain_get (), method->klass);
3507 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
3508 obj = mono_object_unbox (nullable);
3511 /* obj must be already unboxed if needed */
3512 res = mono_runtime_invoke (method, obj, pa, exc);
3514 if (has_byref_nullables) {
3516 * The runtime invoke wrapper already converted byref nullables back,
3517 * and stored them in pa, we just need to copy them back to the
3520 for (i = 0; i < mono_array_length (params); i++) {
3521 MonoType *t = sig->params [i];
3523 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
3524 mono_array_setref (params, i, pa [i]);
3533 arith_overflow (void)
3535 mono_raise_exception (mono_get_exception_overflow ());
3539 * mono_object_allocate:
3540 * @size: number of bytes to allocate
3542 * This is a very simplistic routine until we have our GC-aware
3545 * Returns: an allocated object of size @size, or NULL on failure.
3547 static inline void *
3548 mono_object_allocate (size_t size, MonoVTable *vtable)
3551 mono_stats.new_object_count++;
3552 ALLOC_OBJECT (o, vtable, size);
3558 * mono_object_allocate_ptrfree:
3559 * @size: number of bytes to allocate
3561 * Note that the memory allocated is not zeroed.
3562 * Returns: an allocated object of size @size, or NULL on failure.
3564 static inline void *
3565 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
3568 mono_stats.new_object_count++;
3569 ALLOC_PTRFREE (o, vtable, size);
3573 static inline void *
3574 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
3577 ALLOC_TYPED (o, size, vtable);
3578 mono_stats.new_object_count++;
3585 * @klass: the class of the object that we want to create
3587 * Returns: a newly created object whose definition is
3588 * looked up using @klass. This will not invoke any constructors,
3589 * so the consumer of this routine has to invoke any constructors on
3590 * its own to initialize the object.
3593 mono_object_new (MonoDomain *domain, MonoClass *klass)
3595 MONO_ARCH_SAVE_REGS;
3596 return mono_object_new_specific (mono_class_vtable (domain, klass));
3600 * mono_object_new_specific:
3601 * @vtable: the vtable of the object that we want to create
3603 * Returns: A newly created object with class and domain specified
3607 mono_object_new_specific (MonoVTable *vtable)
3611 MONO_ARCH_SAVE_REGS;
3613 /* check for is_com_object for COM Interop */
3614 if (vtable->remote || vtable->klass->is_com_object)
3617 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
3620 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
3623 mono_class_init (klass);
3625 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
3627 vtable->domain->create_proxy_for_type_method = im;
3630 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
3632 o = mono_runtime_invoke (im, NULL, pa, NULL);
3633 if (o != NULL) return o;
3636 return mono_object_new_alloc_specific (vtable);
3640 mono_object_new_alloc_specific (MonoVTable *vtable)
3644 if (!vtable->klass->has_references) {
3645 o = mono_object_new_ptrfree (vtable);
3646 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3647 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
3649 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
3650 o = mono_object_allocate (vtable->klass->instance_size, vtable);
3652 if (G_UNLIKELY (vtable->klass->has_finalize))
3653 mono_object_register_finalizer (o);
3655 if (G_UNLIKELY (profile_allocs))
3656 mono_profiler_allocation (o, vtable->klass);
3661 mono_object_new_fast (MonoVTable *vtable)
3664 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
3669 mono_object_new_ptrfree (MonoVTable *vtable)
3672 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
3673 #if NEED_TO_ZERO_PTRFREE
3674 /* an inline memset is much faster for the common vcase of small objects
3675 * note we assume the allocated size is a multiple of sizeof (void*).
3677 if (vtable->klass->instance_size < 128) {
3679 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
3680 p = (gpointer*)((char*)obj + sizeof (MonoObject));
3686 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
3693 mono_object_new_ptrfree_box (MonoVTable *vtable)
3696 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
3697 /* the object will be boxed right away, no need to memzero it */
3702 * mono_class_get_allocation_ftn:
3704 * @for_box: the object will be used for boxing
3705 * @pass_size_in_words:
3707 * Return the allocation function appropriate for the given class.
3711 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
3713 *pass_size_in_words = FALSE;
3715 if (!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
3716 profile_allocs = FALSE;
3718 if (vtable->klass->has_finalize || vtable->klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
3719 return mono_object_new_specific;
3721 if (!vtable->klass->has_references) {
3722 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
3724 return mono_object_new_ptrfree_box;
3725 return mono_object_new_ptrfree;
3728 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3730 return mono_object_new_fast;
3733 * FIXME: This is actually slower than mono_object_new_fast, because
3734 * of the overhead of parameter passing.
3737 *pass_size_in_words = TRUE;
3738 #ifdef GC_REDIRECT_TO_LOCAL
3739 return GC_local_gcj_fast_malloc;
3741 return GC_gcj_fast_malloc;
3746 return mono_object_new_specific;
3750 * mono_object_new_from_token:
3751 * @image: Context where the type_token is hosted
3752 * @token: a token of the type that we want to create
3754 * Returns: A newly created object whose definition is
3755 * looked up using @token in the @image image
3758 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
3762 class = mono_class_get (image, token);
3764 return mono_object_new (domain, class);
3769 * mono_object_clone:
3770 * @obj: the object to clone
3772 * Returns: A newly created object who is a shallow copy of @obj
3775 mono_object_clone (MonoObject *obj)
3780 size = obj->vtable->klass->instance_size;
3781 o = mono_object_allocate (size, obj->vtable);
3782 /* do not copy the sync state */
3783 memcpy ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
3786 if (obj->vtable->klass->has_references)
3787 mono_gc_wbarrier_object (o);
3789 if (G_UNLIKELY (profile_allocs))
3790 mono_profiler_allocation (o, obj->vtable->klass);
3792 if (obj->vtable->klass->has_finalize)
3793 mono_object_register_finalizer (o);
3798 * mono_array_full_copy:
3799 * @src: source array to copy
3800 * @dest: destination array
3802 * Copies the content of one array to another with exactly the same type and size.
3805 mono_array_full_copy (MonoArray *src, MonoArray *dest)
3807 mono_array_size_t size;
3808 MonoClass *klass = src->obj.vtable->klass;
3810 MONO_ARCH_SAVE_REGS;
3812 g_assert (klass == dest->obj.vtable->klass);
3814 size = mono_array_length (src);
3815 g_assert (size == mono_array_length (dest));
3816 size *= mono_array_element_size (klass);
3818 if (klass->element_class->valuetype) {
3819 if (klass->element_class->has_references)
3820 mono_value_copy_array (dest, 0, mono_array_addr_with_size (src, 0, 0), mono_array_length (src));
3822 memcpy (&dest->vector, &src->vector, size);
3824 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
3827 memcpy (&dest->vector, &src->vector, size);
3832 * mono_array_clone_in_domain:
3833 * @domain: the domain in which the array will be cloned into
3834 * @array: the array to clone
3836 * This routine returns a copy of the array that is hosted on the
3837 * specified MonoDomain.
3840 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
3843 mono_array_size_t size, i;
3844 mono_array_size_t *sizes;
3845 MonoClass *klass = array->obj.vtable->klass;
3847 MONO_ARCH_SAVE_REGS;
3849 if (array->bounds == NULL) {
3850 size = mono_array_length (array);
3851 o = mono_array_new_full (domain, klass, &size, NULL);
3853 size *= mono_array_element_size (klass);
3855 if (klass->element_class->valuetype) {
3856 if (klass->element_class->has_references)
3857 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
3859 memcpy (&o->vector, &array->vector, size);
3861 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
3864 memcpy (&o->vector, &array->vector, size);
3869 sizes = alloca (klass->rank * sizeof(mono_array_size_t) * 2);
3870 size = mono_array_element_size (klass);
3871 for (i = 0; i < klass->rank; ++i) {
3872 sizes [i] = array->bounds [i].length;
3873 size *= array->bounds [i].length;
3874 sizes [i + klass->rank] = array->bounds [i].lower_bound;
3876 o = mono_array_new_full (domain, klass, sizes, sizes + klass->rank);
3878 if (klass->element_class->valuetype) {
3879 if (klass->element_class->has_references)
3880 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
3882 memcpy (&o->vector, &array->vector, size);
3884 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
3887 memcpy (&o->vector, &array->vector, size);
3895 * @array: the array to clone
3897 * Returns: A newly created array who is a shallow copy of @array
3900 mono_array_clone (MonoArray *array)
3902 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
3905 /* helper macros to check for overflow when calculating the size of arrays */
3906 #ifdef MONO_BIG_ARRAYS
3907 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
3908 #define MYGUINT_MAX MYGUINT64_MAX
3909 #define CHECK_ADD_OVERFLOW_UN(a,b) \
3910 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
3911 #define CHECK_MUL_OVERFLOW_UN(a,b) \
3912 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
3913 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
3915 #define MYGUINT32_MAX 4294967295U
3916 #define MYGUINT_MAX MYGUINT32_MAX
3917 #define CHECK_ADD_OVERFLOW_UN(a,b) \
3918 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
3919 #define CHECK_MUL_OVERFLOW_UN(a,b) \
3920 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
3921 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
3925 * mono_array_new_full:
3926 * @domain: domain where the object is created
3927 * @array_class: array class
3928 * @lengths: lengths for each dimension in the array
3929 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
3931 * This routine creates a new array objects with the given dimensions,
3932 * lower bounds and type.
3935 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, mono_array_size_t *lengths, mono_array_size_t *lower_bounds)
3937 mono_array_size_t byte_len, len, bounds_size;
3943 if (!array_class->inited)
3944 mono_class_init (array_class);
3946 byte_len = mono_array_element_size (array_class);
3949 /* A single dimensional array with a 0 lower bound is the same as an szarray */
3950 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
3952 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
3956 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
3958 for (i = 0; i < array_class->rank; ++i) {
3959 if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
3961 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
3962 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3967 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
3968 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3970 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
3971 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3972 byte_len += sizeof (MonoArray);
3975 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
3976 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3977 byte_len = (byte_len + 3) & ~3;
3978 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
3979 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3980 byte_len += bounds_size;
3983 * Following three lines almost taken from mono_object_new ():
3984 * they need to be kept in sync.
3986 vtable = mono_class_vtable (domain, array_class);
3987 if (!array_class->has_references) {
3988 o = mono_object_allocate_ptrfree (byte_len, vtable);
3989 #if NEED_TO_ZERO_PTRFREE
3990 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
3992 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3993 o = mono_object_allocate_spec (byte_len, vtable);
3995 o = mono_object_allocate (byte_len, vtable);
3998 array = (MonoArray*)o;
3999 array->max_length = len;
4002 MonoArrayBounds *bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
4003 array->bounds = bounds;
4004 for (i = 0; i < array_class->rank; ++i) {
4005 bounds [i].length = lengths [i];
4007 bounds [i].lower_bound = lower_bounds [i];
4011 if (G_UNLIKELY (profile_allocs))
4012 mono_profiler_allocation (o, array_class);
4019 * @domain: domain where the object is created
4020 * @eclass: element class
4021 * @n: number of array elements
4023 * This routine creates a new szarray with @n elements of type @eclass.
4026 mono_array_new (MonoDomain *domain, MonoClass *eclass, mono_array_size_t n)
4030 MONO_ARCH_SAVE_REGS;
4032 ac = mono_array_class_get (eclass, 1);
4035 return mono_array_new_specific (mono_class_vtable (domain, ac), n);
4039 * mono_array_new_specific:
4040 * @vtable: a vtable in the appropriate domain for an initialized class
4041 * @n: number of array elements
4043 * This routine is a fast alternative to mono_array_new() for code which
4044 * can be sure about the domain it operates in.
4047 mono_array_new_specific (MonoVTable *vtable, mono_array_size_t n)
4051 guint32 byte_len, elem_size;
4053 MONO_ARCH_SAVE_REGS;
4055 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
4060 elem_size = mono_array_element_size (vtable->klass);
4061 if (CHECK_MUL_OVERFLOW_UN (n, elem_size)) {
4062 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4065 byte_len = n * elem_size;
4066 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray))) {
4067 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4070 byte_len += sizeof (MonoArray);
4071 if (!vtable->klass->has_references) {
4072 o = mono_object_allocate_ptrfree (byte_len, vtable);
4073 #if NEED_TO_ZERO_PTRFREE
4074 ((MonoArray*)o)->bounds = NULL;
4075 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4077 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4078 o = mono_object_allocate_spec (byte_len, vtable);
4080 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4081 o = mono_object_allocate (byte_len, vtable);
4084 ao = (MonoArray *)o;
4086 if (G_UNLIKELY (profile_allocs))
4087 mono_profiler_allocation (o, vtable->klass);
4093 * mono_string_new_utf16:
4094 * @text: a pointer to an utf16 string
4095 * @len: the length of the string
4097 * Returns: A newly created string object which contains @text.
4100 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
4104 s = mono_string_new_size (domain, len);
4105 g_assert (s != NULL);
4107 memcpy (mono_string_chars (s), text, len * 2);
4113 * mono_string_new_size:
4114 * @text: a pointer to an utf16 string
4115 * @len: the length of the string
4117 * Returns: A newly created string object of @len
4120 mono_string_new_size (MonoDomain *domain, gint32 len)
4124 size_t size = (sizeof (MonoString) + ((len + 1) * 2));
4126 /* overflow ? can't fit it, can't allocate it! */
4128 mono_gc_out_of_memory (-1);
4130 vtable = mono_class_vtable (domain, mono_defaults.string_class);
4132 s = mono_object_allocate_ptrfree (size, vtable);
4135 #if NEED_TO_ZERO_PTRFREE
4138 if (G_UNLIKELY (profile_allocs))
4139 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
4145 * mono_string_new_len:
4146 * @text: a pointer to an utf8 string
4147 * @length: number of bytes in @text to consider
4149 * Returns: A newly created string object which contains @text.
4152 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
4154 GError *error = NULL;
4155 MonoString *o = NULL;
4157 glong items_written;
4159 ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
4162 o = mono_string_new_utf16 (domain, ut, items_written);
4164 g_error_free (error);
4173 * @text: a pointer to an utf8 string
4175 * Returns: A newly created string object which contains @text.
4178 mono_string_new (MonoDomain *domain, const char *text)
4180 GError *error = NULL;
4181 MonoString *o = NULL;
4183 glong items_written;
4188 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
4191 o = mono_string_new_utf16 (domain, ut, items_written);
4193 g_error_free (error);
4196 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
4201 MonoString *o = NULL;
4203 if (!g_utf8_validate (text, -1, &end))
4206 len = g_utf8_strlen (text, -1);
4207 o = mono_string_new_size (domain, len);
4208 str = mono_string_chars (o);
4210 while (text < end) {
4211 *str++ = g_utf8_get_char (text);
4212 text = g_utf8_next_char (text);
4219 * mono_string_new_wrapper:
4220 * @text: pointer to utf8 characters.
4222 * Helper function to create a string object from @text in the current domain.
4225 mono_string_new_wrapper (const char *text)
4227 MonoDomain *domain = mono_domain_get ();
4229 MONO_ARCH_SAVE_REGS;
4232 return mono_string_new (domain, text);
4239 * @class: the class of the value
4240 * @value: a pointer to the unboxed data
4242 * Returns: A newly created object which contains @value.
4245 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
4251 g_assert (class->valuetype);
4252 if (mono_class_is_nullable (class))
4253 return mono_nullable_box (value, class);
4255 vtable = mono_class_vtable (domain, class);
4256 size = mono_class_instance_size (class);
4257 res = mono_object_new_alloc_specific (vtable);
4258 if (G_UNLIKELY (profile_allocs))
4259 mono_profiler_allocation (res, class);
4261 size = size - sizeof (MonoObject);
4264 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
4267 #if NO_UNALIGNED_ACCESS
4268 memcpy ((char *)res + sizeof (MonoObject), value, size);
4272 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
4275 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
4278 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
4281 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
4284 memcpy ((char *)res + sizeof (MonoObject), value, size);
4287 if (class->has_finalize)
4288 mono_object_register_finalizer (res);
4294 * @dest: destination pointer
4295 * @src: source pointer
4296 * @klass: a valuetype class
4298 * Copy a valuetype from @src to @dest. This function must be used
4299 * when @klass contains references fields.
4302 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
4304 int size = mono_class_value_size (klass, NULL);
4305 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
4306 memcpy (dest, src, size);
4310 * mono_value_copy_array:
4311 * @dest: destination array
4312 * @dest_idx: index in the @dest array
4313 * @src: source pointer
4314 * @count: number of items
4316 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
4317 * This function must be used when @klass contains references fields.
4318 * Overlap is handled.
4321 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
4323 int size = mono_array_element_size (dest->obj.vtable->klass);
4324 char *d = mono_array_addr_with_size (dest, size, dest_idx);
4325 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
4326 memmove (d, src, size * count);
4330 * mono_object_get_domain:
4331 * @obj: object to query
4333 * Returns: the MonoDomain where the object is hosted
4336 mono_object_get_domain (MonoObject *obj)
4338 return mono_object_domain (obj);
4342 * mono_object_get_class:
4343 * @obj: object to query
4345 * Returns: the MonOClass of the object.
4348 mono_object_get_class (MonoObject *obj)
4350 return mono_object_class (obj);
4353 * mono_object_get_size:
4354 * @o: object to query
4356 * Returns: the size, in bytes, of @o
4359 mono_object_get_size (MonoObject* o)
4361 MonoClass* klass = mono_object_class (o);
4362 if (klass == mono_defaults.string_class) {
4363 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
4364 } else if (o->vtable->rank) {
4365 MonoArray *array = (MonoArray*)o;
4366 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
4367 if (array->bounds) {
4370 size += sizeof (MonoArrayBounds) * o->vtable->rank;
4374 return mono_class_instance_size (klass);
4379 * mono_object_unbox:
4380 * @obj: object to unbox
4382 * Returns: a pointer to the start of the valuetype boxed in this
4385 * This method will assert if the object passed is not a valuetype.
4388 mono_object_unbox (MonoObject *obj)
4390 /* add assert for valuetypes? */
4391 g_assert (obj->vtable->klass->valuetype);
4392 return ((char*)obj) + sizeof (MonoObject);
4396 * mono_object_isinst:
4398 * @klass: a pointer to a class
4400 * Returns: @obj if @obj is derived from @klass
4403 mono_object_isinst (MonoObject *obj, MonoClass *klass)
4406 mono_class_init (klass);
4408 if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE)
4409 return mono_object_isinst_mbyref (obj, klass);
4414 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
4418 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
4427 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4428 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
4432 MonoClass *oklass = vt->klass;
4433 if ((oklass == mono_defaults.transparent_proxy_class))
4434 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
4436 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
4440 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
4442 MonoDomain *domain = mono_domain_get ();
4444 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
4445 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
4446 MonoMethod *im = NULL;
4449 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
4450 im = mono_object_get_virtual_method (rp, im);
4453 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
4456 res = mono_runtime_invoke (im, rp, pa, NULL);
4458 if (*(MonoBoolean *) mono_object_unbox(res)) {
4459 /* Update the vtable of the remote type, so it can safely cast to this new type */
4460 mono_upgrade_remote_class (domain, obj, klass);
4469 * mono_object_castclass_mbyref:
4471 * @klass: a pointer to a class
4473 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
4476 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
4478 if (!obj) return NULL;
4479 if (mono_object_isinst_mbyref (obj, klass)) return obj;
4481 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
4483 "InvalidCastException"));
4488 MonoDomain *orig_domain;
4494 str_lookup (MonoDomain *domain, gpointer user_data)
4496 LDStrInfo *info = user_data;
4497 if (info->res || domain == info->orig_domain)
4499 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
4505 mono_string_get_pinned (MonoString *str)
4509 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
4510 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
4511 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
4512 news->length = mono_string_length (str);
4517 #define mono_string_get_pinned(str) (str)
4521 mono_string_is_interned_lookup (MonoString *str, int insert)
4523 MonoGHashTable *ldstr_table;
4527 domain = ((MonoObject *)str)->vtable->domain;
4528 ldstr_table = domain->ldstr_table;
4530 if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
4535 str = mono_string_get_pinned (str);
4536 mono_g_hash_table_insert (ldstr_table, str, str);
4540 LDStrInfo ldstr_info;
4541 ldstr_info.orig_domain = domain;
4542 ldstr_info.ins = str;
4543 ldstr_info.res = NULL;
4545 mono_domain_foreach (str_lookup, &ldstr_info);
4546 if (ldstr_info.res) {
4548 * the string was already interned in some other domain:
4549 * intern it in the current one as well.
4551 mono_g_hash_table_insert (ldstr_table, str, str);
4561 * mono_string_is_interned:
4562 * @o: String to probe
4564 * Returns whether the string has been interned.
4567 mono_string_is_interned (MonoString *o)
4569 return mono_string_is_interned_lookup (o, FALSE);
4573 * mono_string_intern:
4574 * @o: String to intern
4576 * Interns the string passed.
4577 * Returns: The interned string.
4580 mono_string_intern (MonoString *str)
4582 return mono_string_is_interned_lookup (str, TRUE);
4587 * @domain: the domain where the string will be used.
4588 * @image: a metadata context
4589 * @idx: index into the user string table.
4591 * Implementation for the ldstr opcode.
4592 * Returns: a loaded string from the @image/@idx combination.
4595 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
4597 MONO_ARCH_SAVE_REGS;
4600 return mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
4602 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
4606 * mono_ldstr_metadata_sig
4607 * @domain: the domain for the string
4608 * @sig: the signature of a metadata string
4610 * Returns: a MonoString for a string stored in the metadata
4613 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
4615 const char *str = sig;
4616 MonoString *o, *interned;
4619 len2 = mono_metadata_decode_blob_size (str, &str);
4622 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
4623 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
4626 guint16 *p2 = (guint16*)mono_string_chars (o);
4627 for (i = 0; i < len2; ++i) {
4628 *p2 = GUINT16_FROM_LE (*p2);
4634 if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
4636 /* o will get garbage collected */
4640 o = mono_string_get_pinned (o);
4641 mono_g_hash_table_insert (domain->ldstr_table, o, o);
4648 * mono_string_to_utf8:
4649 * @s: a System.String
4651 * Return the UTF8 representation for @s.
4652 * the resulting buffer nedds to be freed with g_free().
4655 mono_string_to_utf8 (MonoString *s)
4659 GError *error = NULL;
4665 return g_strdup ("");
4667 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &error);
4669 MonoException *exc = mono_get_exception_argument ("string", error->message);
4670 g_error_free (error);
4671 mono_raise_exception(exc);
4673 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
4674 if (s->length > written) {
4675 /* allocate the total length and copy the part of the string that has been converted */
4676 char *as2 = g_malloc0 (s->length);
4677 memcpy (as2, as, written);
4686 * mono_string_to_utf16:
4689 * Return an null-terminated array of the utf-16 chars
4690 * contained in @s. The result must be freed with g_free().
4691 * This is a temporary helper until our string implementation
4692 * is reworked to always include the null terminating char.
4695 mono_string_to_utf16 (MonoString *s)
4702 as = g_malloc ((s->length * 2) + 2);
4703 as [(s->length * 2)] = '\0';
4704 as [(s->length * 2) + 1] = '\0';
4707 return (gunichar2 *)(as);
4710 memcpy (as, mono_string_chars(s), s->length * 2);
4711 return (gunichar2 *)(as);
4715 * mono_string_from_utf16:
4716 * @data: the UTF16 string (LPWSTR) to convert
4718 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
4720 * Returns: a MonoString.
4723 mono_string_from_utf16 (gunichar2 *data)
4725 MonoDomain *domain = mono_domain_get ();
4731 while (data [len]) len++;
4733 return mono_string_new_utf16 (domain, data, len);
4737 * mono_string_to_utf8_mp:
4738 * @s: a System.String
4740 * Same as mono_string_to_utf8, but allocate the string from a mempool.
4743 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s)
4745 char *r = mono_string_to_utf8 (s);
4752 len = strlen (r) + 1;
4753 mp_s = mono_mempool_alloc (mp, len);
4754 memcpy (mp_s, r, len);
4762 default_ex_handler (MonoException *ex)
4764 MonoObject *o = (MonoObject*)ex;
4765 g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
4769 static MonoExceptionFunc ex_handler = default_ex_handler;
4772 * mono_install_handler:
4773 * @func: exception handler
4775 * This is an internal JIT routine used to install the handler for exceptions
4779 mono_install_handler (MonoExceptionFunc func)
4781 ex_handler = func? func: default_ex_handler;
4785 * mono_raise_exception:
4786 * @ex: exception object
4788 * Signal the runtime that the exception @ex has been raised in unmanaged code.
4791 mono_raise_exception (MonoException *ex)
4794 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
4795 * that will cause gcc to omit the function epilog, causing problems when
4796 * the JIT tries to walk the stack, since the return address on the stack
4797 * will point into the next function in the executable, not this one.
4800 if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class)
4801 MONO_OBJECT_SETREF (mono_thread_current (), abort_exc, ex);
4807 * mono_wait_handle_new:
4808 * @domain: Domain where the object will be created
4809 * @handle: Handle for the wait handle
4811 * Returns: A new MonoWaitHandle created in the given domain for the given handle
4814 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
4816 MonoWaitHandle *res;
4817 gpointer params [1];
4818 static MonoMethod *handle_set;
4820 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.waithandle_class);
4822 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
4824 handle_set = mono_class_get_property_from_name (mono_defaults.waithandle_class, "Handle")->set;
4826 params [0] = &handle;
4827 mono_runtime_invoke (handle_set, res, params, NULL);
4833 mono_wait_handle_get_handle (MonoWaitHandle *handle)
4835 static MonoClassField *f_os_handle;
4836 static MonoClassField *f_safe_handle;
4838 if (!f_os_handle && !f_safe_handle) {
4839 f_os_handle = mono_class_get_field_from_name (mono_defaults.waithandle_class, "os_handle");
4840 f_safe_handle = mono_class_get_field_from_name (mono_defaults.waithandle_class, "safe_wait_handle");
4845 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
4849 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
4855 * mono_async_result_new:
4856 * @domain:domain where the object will be created.
4857 * @handle: wait handle.
4858 * @state: state to pass to AsyncResult
4859 * @data: C closure data.
4861 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
4862 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
4866 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
4868 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
4869 MonoMethod *method = mono_get_context_capture_method ();
4871 /* we must capture the execution context from the original thread */
4873 MONO_OBJECT_SETREF (res, execution_context, mono_runtime_invoke (method, NULL, NULL, NULL));
4874 /* note: result may be null if the flow is suppressed */
4878 MONO_OBJECT_SETREF (res, object_data, object_data);
4879 MONO_OBJECT_SETREF (res, async_state, state);
4881 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
4883 res->sync_completed = FALSE;
4884 res->completed = FALSE;
4890 mono_message_init (MonoDomain *domain,
4891 MonoMethodMessage *this,
4892 MonoReflectionMethod *method,
4893 MonoArray *out_args)
4895 static MonoClass *object_array_klass;
4896 static MonoClass *byte_array_klass;
4897 static MonoClass *string_array_klass;
4898 MonoMethodSignature *sig = mono_method_signature (method->method);
4904 if (!object_array_klass) {
4907 klass = mono_array_class_get (mono_defaults.object_class, 1);
4910 mono_memory_barrier ();
4911 object_array_klass = klass;
4913 klass = mono_array_class_get (mono_defaults.byte_class, 1);
4916 mono_memory_barrier ();
4917 byte_array_klass = klass;
4919 klass = mono_array_class_get (mono_defaults.string_class, 1);
4922 mono_memory_barrier ();
4923 string_array_klass = klass;
4926 MONO_OBJECT_SETREF (this, method, method);
4928 MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
4929 MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
4930 this->async_result = NULL;
4931 this->call_type = CallType_Sync;
4933 names = g_new (char *, sig->param_count);
4934 mono_method_get_param_names (method->method, (const char **) names);
4935 MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
4937 for (i = 0; i < sig->param_count; i++) {
4938 name = mono_string_new (domain, names [i]);
4939 mono_array_setref (this->names, i, name);
4943 for (i = 0, j = 0; i < sig->param_count; i++) {
4944 if (sig->params [i]->byref) {
4946 MonoObject* arg = mono_array_get (out_args, gpointer, j);
4947 mono_array_setref (this->args, i, arg);
4951 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
4955 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
4958 mono_array_set (this->arg_types, guint8, i, arg_type);
4963 * mono_remoting_invoke:
4964 * @real_proxy: pointer to a RealProxy object
4965 * @msg: The MonoMethodMessage to execute
4966 * @exc: used to store exceptions
4967 * @out_args: used to store output arguments
4969 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
4970 * IMessage interface and it is not trivial to extract results from there. So
4971 * we call an helper method PrivateInvoke instead of calling
4972 * RealProxy::Invoke() directly.
4974 * Returns: the result object.
4977 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
4978 MonoObject **exc, MonoArray **out_args)
4980 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
4983 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
4986 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
4988 real_proxy->vtable->domain->private_invoke_method = im;
4991 pa [0] = real_proxy;
4996 return mono_runtime_invoke (im, NULL, pa, exc);
5000 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
5001 MonoObject **exc, MonoArray **out_args)
5003 static MonoClass *object_array_klass;
5006 MonoMethodSignature *sig;
5008 int i, j, outarg_count = 0;
5010 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5012 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
5013 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5014 target = tp->rp->unwrapped_server;
5016 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
5020 domain = mono_domain_get ();
5021 method = msg->method->method;
5022 sig = mono_method_signature (method);
5024 for (i = 0; i < sig->param_count; i++) {
5025 if (sig->params [i]->byref)
5029 if (!object_array_klass) {
5032 klass = mono_array_class_get (mono_defaults.object_class, 1);
5035 mono_memory_barrier ();
5036 object_array_klass = klass;
5039 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
5040 *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
5043 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
5045 for (i = 0, j = 0; i < sig->param_count; i++) {
5046 if (sig->params [i]->byref) {
5048 arg = mono_array_get (msg->args, gpointer, i);
5049 mono_array_setref (*out_args, j, arg);
5058 * mono_print_unhandled_exception:
5059 * @exc: The exception
5061 * Prints the unhandled exception.
5064 mono_print_unhandled_exception (MonoObject *exc)
5066 char *message = (char *) "";
5070 gboolean free_message = FALSE;
5072 if (mono_object_isinst (exc, mono_defaults.exception_class)) {
5073 klass = exc->vtable->klass;
5075 while (klass && method == NULL) {
5076 method = mono_class_get_method_from_name_flags (klass, "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
5078 klass = klass->parent;
5083 str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL);
5085 message = mono_string_to_utf8 (str);
5086 free_message = TRUE;
5091 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
5092 * exc->vtable->klass->name, message);
5094 g_printerr ("\nUnhandled Exception: %s\n", message);
5101 * mono_delegate_ctor:
5102 * @this: pointer to an uninitialized delegate object
5103 * @target: target object
5104 * @addr: pointer to native code
5107 * Initialize a delegate and sets a specific method, not the one
5108 * associated with addr. This is useful when sharing generic code.
5109 * In that case addr will most probably not be associated with the
5110 * correct instantiation of the method.
5113 mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer addr, MonoMethod *method)
5115 MonoDelegate *delegate = (MonoDelegate *)this;
5122 delegate->method = method;
5124 class = this->vtable->klass;
5125 mono_stats.delegate_creations++;
5127 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5129 method = mono_marshal_get_remoting_invoke (method);
5130 delegate->method_ptr = mono_compile_method (method);
5131 MONO_OBJECT_SETREF (delegate, target, target);
5132 } else if (mono_method_signature (method)->hasthis && method->klass->valuetype) {
5133 method = mono_marshal_get_unbox_wrapper (method);
5134 delegate->method_ptr = mono_compile_method (method);
5135 MONO_OBJECT_SETREF (delegate, target, target);
5137 delegate->method_ptr = addr;
5138 MONO_OBJECT_SETREF (delegate, target, target);
5141 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->klass);
5145 * mono_delegate_ctor:
5146 * @this: pointer to an uninitialized delegate object
5147 * @target: target object
5148 * @addr: pointer to native code
5150 * This is used to initialize a delegate.
5153 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
5155 MonoDomain *domain = mono_domain_get ();
5157 MonoMethod *method = NULL;
5161 if ((ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr)))) {
5162 method = ji->method;
5163 g_assert (!method->klass->generic_container);
5166 mono_delegate_ctor_with_method (this, target, addr, method);
5170 * mono_method_call_message_new:
5171 * @method: method to encapsulate
5172 * @params: parameters to the method
5173 * @invoke: optional, delegate invoke.
5174 * @cb: async callback delegate.
5175 * @state: state passed to the async callback.
5177 * Translates arguments pointers into a MonoMethodMessage.
5180 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
5181 MonoDelegate **cb, MonoObject **state)
5183 MonoDomain *domain = mono_domain_get ();
5184 MonoMethodSignature *sig = mono_method_signature (method);
5185 MonoMethodMessage *msg;
5188 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5191 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
5192 count = sig->param_count - 2;
5194 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
5195 count = sig->param_count;
5198 for (i = 0; i < count; i++) {
5203 if (sig->params [i]->byref)
5204 vpos = *((gpointer *)params [i]);
5208 type = sig->params [i]->type;
5209 class = mono_class_from_mono_type (sig->params [i]);
5211 if (class->valuetype)
5212 arg = mono_value_box (domain, class, vpos);
5214 arg = *((MonoObject **)vpos);
5216 mono_array_setref (msg->args, i, arg);
5219 if (cb != NULL && state != NULL) {
5220 *cb = *((MonoDelegate **)params [i]);
5222 *state = *((MonoObject **)params [i]);
5229 * mono_method_return_message_restore:
5231 * Restore results from message based processing back to arguments pointers
5234 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
5236 MonoMethodSignature *sig = mono_method_signature (method);
5237 int i, j, type, size, out_len;
5239 if (out_args == NULL)
5241 out_len = mono_array_length (out_args);
5245 for (i = 0, j = 0; i < sig->param_count; i++) {
5246 MonoType *pt = sig->params [i];
5251 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
5253 arg = mono_array_get (out_args, gpointer, j);
5257 case MONO_TYPE_VOID:
5258 g_assert_not_reached ();
5262 case MONO_TYPE_BOOLEAN:
5265 case MONO_TYPE_CHAR:
5272 case MONO_TYPE_VALUETYPE: {
5274 size = mono_class_value_size (((MonoObject*)arg)->vtable->klass, NULL);
5275 memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
5278 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
5279 memset (*((gpointer *)params [i]), 0, size);
5283 case MONO_TYPE_STRING:
5284 case MONO_TYPE_CLASS:
5285 case MONO_TYPE_ARRAY:
5286 case MONO_TYPE_SZARRAY:
5287 case MONO_TYPE_OBJECT:
5288 **((MonoObject ***)params [i]) = (MonoObject *)arg;
5291 g_assert_not_reached ();
5300 * mono_load_remote_field:
5301 * @this: pointer to an object
5302 * @klass: klass of the object containing @field
5303 * @field: the field to load
5304 * @res: a storage to store the result
5306 * This method is called by the runtime on attempts to load fields of
5307 * transparent proxy objects. @this points to such TP, @klass is the class of
5308 * the object containing @field. @res is a storage location which can be
5309 * used to store the result.
5311 * Returns: an address pointing to the value of field.
5314 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
5316 static MonoMethod *getter = NULL;
5317 MonoDomain *domain = mono_domain_get ();
5318 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5319 MonoClass *field_class;
5320 MonoMethodMessage *msg;
5321 MonoArray *out_args;
5325 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5326 g_assert (res != NULL);
5328 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5329 mono_field_get_value (tp->rp->unwrapped_server, field, res);
5334 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
5338 field_class = mono_class_from_mono_type (field->type);
5340 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5341 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
5342 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
5344 full_name = mono_type_get_full_name (klass);
5345 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5346 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5349 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5351 if (exc) mono_raise_exception ((MonoException *)exc);
5353 if (mono_array_length (out_args) == 0)
5356 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
5358 if (field_class->valuetype) {
5359 return ((char *)*res) + sizeof (MonoObject);
5365 * mono_load_remote_field_new:
5370 * Missing documentation.
5373 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
5375 static MonoMethod *getter = NULL;
5376 MonoDomain *domain = mono_domain_get ();
5377 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5378 MonoClass *field_class;
5379 MonoMethodMessage *msg;
5380 MonoArray *out_args;
5381 MonoObject *exc, *res;
5384 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5386 field_class = mono_class_from_mono_type (field->type);
5388 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5390 if (field_class->valuetype) {
5391 res = mono_object_new (domain, field_class);
5392 val = ((gchar *) res) + sizeof (MonoObject);
5396 mono_field_get_value (tp->rp->unwrapped_server, field, val);
5401 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
5405 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5406 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
5408 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
5410 full_name = mono_type_get_full_name (klass);
5411 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5412 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5415 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5417 if (exc) mono_raise_exception ((MonoException *)exc);
5419 if (mono_array_length (out_args) == 0)
5422 res = mono_array_get (out_args, MonoObject *, 0);
5428 * mono_store_remote_field:
5429 * @this: pointer to an object
5430 * @klass: klass of the object containing @field
5431 * @field: the field to load
5432 * @val: the value/object to store
5434 * This method is called by the runtime on attempts to store fields of
5435 * transparent proxy objects. @this points to such TP, @klass is the class of
5436 * the object containing @field. @val is the new value to store in @field.
5439 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
5441 static MonoMethod *setter = NULL;
5442 MonoDomain *domain = mono_domain_get ();
5443 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5444 MonoClass *field_class;
5445 MonoMethodMessage *msg;
5446 MonoArray *out_args;
5451 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5453 field_class = mono_class_from_mono_type (field->type);
5455 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5456 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
5457 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
5462 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
5466 if (field_class->valuetype)
5467 arg = mono_value_box (domain, field_class, val);
5469 arg = *((MonoObject **)val);
5472 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5473 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
5475 full_name = mono_type_get_full_name (klass);
5476 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5477 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5478 mono_array_setref (msg->args, 2, arg);
5481 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5483 if (exc) mono_raise_exception ((MonoException *)exc);
5487 * mono_store_remote_field_new:
5493 * Missing documentation
5496 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
5498 static MonoMethod *setter = NULL;
5499 MonoDomain *domain = mono_domain_get ();
5500 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5501 MonoClass *field_class;
5502 MonoMethodMessage *msg;
5503 MonoArray *out_args;
5507 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5509 field_class = mono_class_from_mono_type (field->type);
5511 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5512 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
5513 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
5518 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
5522 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5523 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
5525 full_name = mono_type_get_full_name (klass);
5526 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5527 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5528 mono_array_setref (msg->args, 2, arg);
5531 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5533 if (exc) mono_raise_exception ((MonoException *)exc);
5537 * mono_create_ftnptr:
5539 * Given a function address, create a function descriptor for it.
5540 * This is only needed on IA64 and PPC64.
5543 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
5548 mono_domain_lock (domain);
5549 desc = mono_code_manager_reserve (domain->code_mp, 2 * sizeof (gpointer));
5550 mono_domain_unlock (domain);
5556 #elif defined(__ppc64__) || defined(__powerpc64__)
5559 mono_domain_lock (domain);
5560 desc = mono_code_manager_reserve (domain->code_mp, 3 * sizeof (gpointer));
5561 mono_domain_unlock (domain);
5574 * mono_get_addr_from_ftnptr:
5576 * Given a pointer to a function descriptor, return the function address.
5577 * This is only needed on IA64 and PPC64.
5580 mono_get_addr_from_ftnptr (gpointer descr)
5582 #if defined(__ia64__) || defined(__ppc64__) || defined(__powerpc64__)
5583 return *(gpointer*)descr;
5591 * mono_string_chars:
5594 * Returns a pointer to the UCS16 characters stored in the MonoString
5597 mono_string_chars(MonoString *s)
5599 /* This method is here only for documentation extraction, this is a macro */
5603 * mono_string_length:
5606 * Returns the lenght in characters of the string
5609 mono_string_length (MonoString *s)
5611 /* This method is here only for documentation extraction, this is a macro */