2 * object.c: Object creation for the Mono runtime
5 * Miguel de Icaza (miguel@ximian.com)
6 * Paolo Molaro (lupus@ximian.com)
8 * (C) 2001-2004 Ximian, Inc.
15 #include <mono/metadata/mono-endian.h>
16 #include <mono/metadata/tabledefs.h>
17 #include <mono/metadata/tokentype.h>
18 #include <mono/metadata/loader.h>
19 #include <mono/metadata/object.h>
20 #include <mono/metadata/gc-internal.h>
21 #include <mono/metadata/exception.h>
22 #include <mono/metadata/domain-internals.h>
23 #include "mono/metadata/metadata-internals.h"
24 #include "mono/metadata/class-internals.h"
25 #include <mono/metadata/assembly.h>
26 #include <mono/metadata/threadpool.h>
27 #include <mono/metadata/marshal.h>
28 #include "mono/metadata/debug-helpers.h"
29 #include "mono/metadata/marshal.h"
30 #include <mono/metadata/threads.h>
31 #include <mono/metadata/threads-types.h>
32 #include <mono/metadata/environment.h>
33 #include "mono/metadata/profiler-private.h"
34 #include "mono/metadata/security-manager.h"
35 #include "mono/metadata/mono-debug-debugger.h"
36 #include <mono/metadata/gc-internal.h>
37 #include <mono/utils/strenc.h>
38 #include <mono/utils/mono-counters.h>
41 #define NEED_TO_ZERO_PTRFREE 1
42 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = GC_MALLOC_ATOMIC ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
43 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = GC_MALLOC ((size)); (obj)->vtable = (vt);} while (0)
44 #ifdef HAVE_GC_GCJ_MALLOC
45 #define GC_NO_DESCRIPTOR ((gpointer)(0 | GC_DS_LENGTH))
46 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_GCJ_MALLOC ((size),(type)); } while (0)
48 #define GC_NO_DESCRIPTOR (NULL)
49 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_MALLOC ((size)); *(gpointer*)dest = (type);} while (0)
53 #define GC_NO_DESCRIPTOR (NULL)
54 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
55 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
56 #define ALLOC_TYPED(dest,size,type) do { (dest) = mono_gc_alloc_obj (type, size);} while (0)
58 #define NEED_TO_ZERO_PTRFREE 1
59 #define GC_NO_DESCRIPTOR (NULL)
60 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = malloc ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
61 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = calloc (1, (size)); (obj)->vtable = (vt);} while (0)
62 #define ALLOC_TYPED(dest,size,type) do { (dest) = calloc (1, (size)); *(gpointer*)dest = (type);} while (0)
66 static MonoObject* mono_object_new_ptrfree (MonoVTable *vtable);
67 static MonoObject* mono_object_new_ptrfree_box (MonoVTable *vtable);
70 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value);
73 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig);
75 #define ldstr_lock() EnterCriticalSection (&ldstr_section)
76 #define ldstr_unlock() LeaveCriticalSection (&ldstr_section)
77 static CRITICAL_SECTION ldstr_section;
79 static gboolean profile_allocs = TRUE;
82 mono_runtime_object_init (MonoObject *this)
84 MonoMethod *method = NULL;
85 MonoClass *klass = this->vtable->klass;
87 method = mono_class_get_method_from_name (klass, ".ctor", 0);
90 if (method->klass->valuetype)
91 this = mono_object_unbox (this);
92 mono_runtime_invoke (method, this, NULL, NULL);
95 /* The pseudo algorithm for type initialization from the spec
96 Note it doesn't say anything about domains - only threads.
98 2. If the type is initialized you are done.
99 2.1. If the type is not yet initialized, try to take an
101 2.2. If successful, record this thread as responsible for
102 initializing the type and proceed to step 2.3.
103 2.2.1. If not, see whether this thread or any thread
104 waiting for this thread to complete already holds the lock.
105 2.2.2. If so, return since blocking would create a deadlock. This thread
106 will now see an incompletely initialized state for the type,
107 but no deadlock will arise.
108 2.2.3 If not, block until the type is initialized then return.
109 2.3 Initialize the parent type and then all interfaces implemented
111 2.4 Execute the type initialization code for this type.
112 2.5 Mark the type as initialized, release the initialization lock,
113 awaken any threads waiting for this type to be initialized,
120 guint32 initializing_tid;
121 guint32 waiting_count;
123 CRITICAL_SECTION initialization_section;
124 } TypeInitializationLock;
126 /* for locking access to type_initialization_hash and blocked_thread_hash */
127 #define mono_type_initialization_lock() EnterCriticalSection (&type_initialization_section)
128 #define mono_type_initialization_unlock() LeaveCriticalSection (&type_initialization_section)
129 static CRITICAL_SECTION type_initialization_section;
131 /* from vtable to lock */
132 static GHashTable *type_initialization_hash;
134 /* from thread id to thread id being waited on */
135 static GHashTable *blocked_thread_hash;
138 static MonoThread *main_thread;
141 * mono_thread_set_main:
142 * @thread: thread to set as the main thread
144 * This function can be used to instruct the runtime to treat @thread
145 * as the main thread, ie, the thread that would normally execute the Main()
146 * method. This basically means that at the end of @thread, the runtime will
147 * wait for the existing foreground threads to quit and other such details.
150 mono_thread_set_main (MonoThread *thread)
152 main_thread = thread;
156 mono_thread_get_main (void)
162 mono_type_initialization_init (void)
164 InitializeCriticalSection (&type_initialization_section);
165 type_initialization_hash = g_hash_table_new (NULL, NULL);
166 blocked_thread_hash = g_hash_table_new (NULL, NULL);
167 InitializeCriticalSection (&ldstr_section);
171 mono_type_initialization_cleanup (void)
174 /* This is causing race conditions with
175 * mono_release_type_locks
177 DeleteCriticalSection (&type_initialization_section);
179 DeleteCriticalSection (&ldstr_section);
183 * get_type_init_exception_for_vtable:
185 * Return the stored type initialization exception for VTABLE.
187 static MonoException*
188 get_type_init_exception_for_vtable (MonoVTable *vtable)
190 MonoDomain *domain = vtable->domain;
191 MonoClass *klass = vtable->klass;
195 g_assert (vtable->init_failed);
198 * If the initializing thread was rudely aborted, the exception is not stored
202 mono_domain_lock (domain);
203 if (domain->type_init_exception_hash)
204 ex = mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
205 mono_domain_unlock (domain);
208 if (klass->name_space && *klass->name_space)
209 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
211 full_name = g_strdup (klass->name);
212 ex = mono_get_exception_type_initialization (full_name, NULL);
219 * mono_runtime_class_init:
220 * @vtable: vtable that needs to be initialized
222 * This routine calls the class constructor for @vtable.
225 mono_runtime_class_init (MonoVTable *vtable)
227 mono_runtime_class_init_full (vtable, TRUE);
231 * mono_runtime_class_init_full:
232 * @vtable that neeeds to be initialized
233 * @raise_exception is TRUE, exceptions are raised intead of returned
237 mono_runtime_class_init_full (MonoVTable *vtable, gboolean raise_exception)
240 MonoException *exc_to_throw;
241 MonoMethod *method = NULL;
247 if (vtable->initialized)
251 klass = vtable->klass;
253 if (!klass->image->checked_module_cctor) {
254 mono_image_check_for_module_cctor (klass->image);
255 if (klass->image->has_module_cctor) {
256 MonoClass *module_klass = mono_class_get (klass->image, MONO_TOKEN_TYPE_DEF | 1);
257 mono_runtime_class_init (mono_class_vtable (vtable->domain, module_klass));
260 method = mono_class_get_cctor (klass);
263 MonoDomain *domain = vtable->domain;
264 TypeInitializationLock *lock;
265 guint32 tid = GetCurrentThreadId();
266 int do_initialization = 0;
267 MonoDomain *last_domain = NULL;
269 mono_type_initialization_lock ();
270 /* double check... */
271 if (vtable->initialized) {
272 mono_type_initialization_unlock ();
275 if (vtable->init_failed) {
276 mono_type_initialization_unlock ();
278 /* The type initialization already failed once, rethrow the same exception */
280 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
281 return get_type_init_exception_for_vtable (vtable);
283 lock = g_hash_table_lookup (type_initialization_hash, vtable);
285 /* This thread will get to do the initialization */
286 if (mono_domain_get () != domain) {
287 /* Transfer into the target domain */
288 last_domain = mono_domain_get ();
289 if (!mono_domain_set (domain, FALSE)) {
290 vtable->initialized = 1;
291 mono_type_initialization_unlock ();
293 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
294 return mono_get_exception_appdomain_unloaded ();
297 lock = g_malloc (sizeof(TypeInitializationLock));
298 InitializeCriticalSection (&lock->initialization_section);
299 lock->initializing_tid = tid;
300 lock->waiting_count = 1;
302 /* grab the vtable lock while this thread still owns type_initialization_section */
303 EnterCriticalSection (&lock->initialization_section);
304 g_hash_table_insert (type_initialization_hash, vtable, lock);
305 do_initialization = 1;
308 TypeInitializationLock *pending_lock;
310 if (lock->initializing_tid == tid || lock->done) {
311 mono_type_initialization_unlock ();
314 /* see if the thread doing the initialization is already blocked on this thread */
315 blocked = GUINT_TO_POINTER (lock->initializing_tid);
316 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
317 if (pending_lock->initializing_tid == tid) {
318 if (!pending_lock->done) {
319 mono_type_initialization_unlock ();
322 /* the thread doing the initialization is blocked on this thread,
323 but on a lock that has already been freed. It just hasn't got
328 blocked = GUINT_TO_POINTER (pending_lock->initializing_tid);
330 ++lock->waiting_count;
331 /* record the fact that we are waiting on the initializing thread */
332 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
334 mono_type_initialization_unlock ();
336 if (do_initialization) {
337 mono_runtime_invoke (method, NULL, NULL, (MonoObject **) &exc);
339 /* If the initialization failed, mark the class as unusable. */
340 /* Avoid infinite loops */
342 (klass->image == mono_defaults.corlib &&
343 !strcmp (klass->name_space, "System") &&
344 !strcmp (klass->name, "TypeInitializationException")))) {
345 vtable->init_failed = 1;
347 if (klass->name_space && *klass->name_space)
348 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
350 full_name = g_strdup (klass->name);
351 exc_to_throw = mono_get_exception_type_initialization (full_name, exc);
355 * Store the exception object so it could be thrown on subsequent
358 mono_domain_lock (domain);
359 if (!domain->type_init_exception_hash)
360 domain->type_init_exception_hash = mono_g_hash_table_new_type (mono_aligned_addr_hash, NULL, MONO_HASH_VALUE_GC);
361 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
362 mono_domain_unlock (domain);
366 mono_domain_set (last_domain, TRUE);
368 LeaveCriticalSection (&lock->initialization_section);
370 /* this just blocks until the initializing thread is done */
371 EnterCriticalSection (&lock->initialization_section);
372 LeaveCriticalSection (&lock->initialization_section);
375 mono_type_initialization_lock ();
376 if (lock->initializing_tid != tid)
377 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
378 --lock->waiting_count;
379 if (lock->waiting_count == 0) {
380 DeleteCriticalSection (&lock->initialization_section);
381 g_hash_table_remove (type_initialization_hash, vtable);
384 if (!vtable->init_failed)
385 vtable->initialized = 1;
386 mono_type_initialization_unlock ();
388 if (vtable->init_failed) {
389 /* Either we were the initializing thread or we waited for the initialization */
391 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
392 return get_type_init_exception_for_vtable (vtable);
395 vtable->initialized = 1;
402 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
404 MonoVTable *vtable = (MonoVTable*)key;
406 TypeInitializationLock *lock = (TypeInitializationLock*) value;
407 if (lock->initializing_tid == GPOINTER_TO_UINT (user) && !lock->done) {
410 * Have to set this since it cannot be set by the normal code in
411 * mono_runtime_class_init (). In this case, the exception object is not stored,
412 * and get_type_init_exception_for_class () needs to be aware of this.
414 vtable->init_failed = 1;
415 LeaveCriticalSection (&lock->initialization_section);
416 --lock->waiting_count;
417 if (lock->waiting_count == 0) {
418 DeleteCriticalSection (&lock->initialization_section);
427 mono_release_type_locks (MonoThread *thread)
429 mono_type_initialization_lock ();
430 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, (gpointer)(gsize)(thread->tid));
431 mono_type_initialization_unlock ();
435 default_trampoline (MonoMethod *method)
441 default_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
443 g_assert_not_reached ();
449 default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target)
451 g_error ("remoting not installed");
456 default_delegate_trampoline (MonoClass *klass)
458 g_assert_not_reached ();
462 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
463 static MonoJumpTrampoline arch_create_jump_trampoline = default_jump_trampoline;
464 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
465 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
466 static MonoImtThunkBuilder imt_thunk_builder = NULL;
467 #define ARCH_USE_IMT (imt_thunk_builder != NULL)
468 #if (MONO_IMT_SIZE > 32)
469 #error "MONO_IMT_SIZE cannot be larger than 32"
473 mono_install_trampoline (MonoTrampoline func)
475 arch_create_jit_trampoline = func? func: default_trampoline;
479 mono_install_jump_trampoline (MonoJumpTrampoline func)
481 arch_create_jump_trampoline = func? func: default_jump_trampoline;
485 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
487 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
491 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
493 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
497 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
498 imt_thunk_builder = func;
501 static MonoCompileFunc default_mono_compile_method = NULL;
504 * mono_install_compile_method:
505 * @func: function to install
507 * This is a VM internal routine
510 mono_install_compile_method (MonoCompileFunc func)
512 default_mono_compile_method = func;
516 * mono_compile_method:
517 * @method: The method to compile.
519 * This JIT-compiles the method, and returns the pointer to the native code
523 mono_compile_method (MonoMethod *method)
525 if (!default_mono_compile_method) {
526 g_error ("compile method called on uninitialized runtime");
529 return default_mono_compile_method (method);
533 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
535 return arch_create_jump_trampoline (domain, method, add_sync_wrapper);
539 mono_runtime_create_delegate_trampoline (MonoClass *klass)
541 return arch_create_delegate_trampoline (klass);
544 static MonoFreeMethodFunc default_mono_free_method = NULL;
547 * mono_install_free_method:
548 * @func: pointer to the MonoFreeMethodFunc used to release a method
550 * This is an internal VM routine, it is used for the engines to
551 * register a handler to release the resources associated with a method.
553 * Methods are freed when no more references to the delegate that holds
557 mono_install_free_method (MonoFreeMethodFunc func)
559 default_mono_free_method = func;
563 * mono_runtime_free_method:
564 * @domain; domain where the method is hosted
565 * @method: method to release
567 * This routine is invoked to free the resources associated with
568 * a method that has been JIT compiled. This is used to discard
569 * methods that were used only temporarily (for example, used in marshalling)
573 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
575 if (default_mono_free_method != NULL)
576 default_mono_free_method (domain, method);
578 mono_free_method (method);
582 * The vtables in the root appdomain are assumed to be reachable by other
583 * roots, and we don't use typed allocation in the other domains.
586 /* The sync block is no longer a GC pointer */
587 #define GC_HEADER_BITMAP (0)
589 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
592 compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
594 MonoClassField *field;
600 max_size = mono_class_data_size (class) / sizeof (gpointer);
602 max_size = class->instance_size / sizeof (gpointer);
603 if (max_size >= size) {
604 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
607 for (p = class; p != NULL; p = p->parent) {
608 gpointer iter = NULL;
609 while ((field = mono_class_get_fields (p, &iter))) {
613 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
615 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
618 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
621 /* FIXME: should not happen, flag as type load error */
622 if (field->type->byref)
625 pos = field->offset / sizeof (gpointer);
628 type = mono_type_get_underlying_type (field->type);
629 switch (type->type) {
632 case MONO_TYPE_FNPTR:
634 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
639 if (class->image != mono_defaults.corlib)
642 case MONO_TYPE_STRING:
643 case MONO_TYPE_SZARRAY:
644 case MONO_TYPE_CLASS:
645 case MONO_TYPE_OBJECT:
646 case MONO_TYPE_ARRAY:
647 g_assert ((field->offset % sizeof(gpointer)) == 0);
649 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
650 *max_set = MAX (*max_set, pos);
652 case MONO_TYPE_GENERICINST:
653 if (!mono_type_generic_inst_is_valuetype (type)) {
654 g_assert ((field->offset % sizeof(gpointer)) == 0);
656 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
657 *max_set = MAX (*max_set, pos);
662 case MONO_TYPE_VALUETYPE: {
663 MonoClass *fclass = mono_class_from_mono_type (field->type);
664 if (fclass->has_references) {
665 /* remove the object header */
666 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
680 case MONO_TYPE_BOOLEAN:
684 g_assert_not_reached ();
696 * similar to the above, but sets the bits in the bitmap for any non-ref field
697 * and ignores static fields
700 compute_class_non_ref_bitmap (MonoClass *class, gsize *bitmap, int size, int offset)
702 MonoClassField *field;
707 max_size = class->instance_size / sizeof (gpointer);
708 if (max_size >= size) {
709 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
712 for (p = class; p != NULL; p = p->parent) {
713 gpointer iter = NULL;
714 while ((field = mono_class_get_fields (p, &iter))) {
717 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
719 /* FIXME: should not happen, flag as type load error */
720 if (field->type->byref)
723 pos = field->offset / sizeof (gpointer);
726 type = mono_type_get_underlying_type (field->type);
727 switch (type->type) {
728 #if SIZEOF_VOID_P == 8
732 case MONO_TYPE_FNPTR:
737 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
738 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
739 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
742 #if SIZEOF_VOID_P == 4
746 case MONO_TYPE_FNPTR:
751 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
752 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
753 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
759 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
760 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
761 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
764 case MONO_TYPE_BOOLEAN:
767 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
769 case MONO_TYPE_STRING:
770 case MONO_TYPE_SZARRAY:
771 case MONO_TYPE_CLASS:
772 case MONO_TYPE_OBJECT:
773 case MONO_TYPE_ARRAY:
775 case MONO_TYPE_GENERICINST:
776 if (!mono_type_generic_inst_is_valuetype (type)) {
781 case MONO_TYPE_VALUETYPE: {
782 MonoClass *fclass = mono_class_from_mono_type (field->type);
783 /* remove the object header */
784 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
788 g_assert_not_reached ();
797 * mono_class_insecure_overlapping:
798 * check if a class with explicit layout has references and non-references
799 * fields overlapping.
801 * Returns: TRUE if it is insecure to load the type.
804 mono_class_insecure_overlapping (MonoClass *klass)
808 gsize default_bitmap [4] = {0};
810 gsize default_nrbitmap [4] = {0};
811 int i, insecure = FALSE;
814 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
815 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
817 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
818 int idx = i % (sizeof (bitmap [0]) * 8);
819 if (bitmap [idx] & nrbitmap [idx]) {
824 if (bitmap != default_bitmap)
826 if (nrbitmap != default_nrbitmap)
829 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
837 mono_string_alloc (int length)
839 return mono_string_new_size (mono_domain_get (), length);
843 mono_class_compute_gc_descriptor (MonoClass *class)
847 gsize default_bitmap [4] = {0};
848 static gboolean gcj_inited = FALSE;
853 mono_register_jit_icall (mono_object_new_ptrfree, "mono_object_new_ptrfree", mono_create_icall_signature ("object ptr"), FALSE);
854 mono_register_jit_icall (mono_object_new_ptrfree_box, "mono_object_new_ptrfree_box", mono_create_icall_signature ("object ptr"), FALSE);
855 mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
856 mono_register_jit_icall (mono_string_alloc, "mono_string_alloc", mono_create_icall_signature ("object int"), FALSE);
858 #ifdef HAVE_GC_GCJ_MALLOC
860 * This is not needed unless the relevant code in mono_get_allocation_ftn () is
864 #ifdef GC_REDIRECT_TO_LOCAL
865 mono_register_jit_icall (GC_local_gcj_malloc, "GC_local_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
866 mono_register_jit_icall (GC_local_gcj_fast_malloc, "GC_local_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
868 mono_register_jit_icall (GC_gcj_malloc, "GC_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
869 mono_register_jit_icall (GC_gcj_fast_malloc, "GC_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
874 mono_loader_unlock ();
878 mono_class_init (class);
880 if (class->gc_descr_inited)
883 class->gc_descr_inited = TRUE;
884 class->gc_descr = GC_NO_DESCRIPTOR;
886 bitmap = default_bitmap;
887 if (class == mono_defaults.string_class) {
888 class->gc_descr = (gpointer)mono_gc_make_descr_for_string (bitmap, 2);
889 } else if (class->rank) {
890 mono_class_compute_gc_descriptor (class->element_class);
891 if (!class->element_class->valuetype) {
893 class->gc_descr = mono_gc_make_descr_for_array (TRUE, &abm, 1, sizeof (gpointer));
894 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
895 class->name_space, class->name);*/
897 /* remove the object header */
898 bitmap = compute_class_bitmap (class->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
899 class->gc_descr = mono_gc_make_descr_for_array (TRUE, bitmap, mono_array_element_size (class) / sizeof (gpointer), mono_array_element_size (class));
900 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
901 class->name_space, class->name);*/
902 if (bitmap != default_bitmap)
906 /*static int count = 0;
909 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
910 class->gc_descr = (gpointer)mono_gc_make_descr_for_object (bitmap, max_set + 1, class->instance_size);
912 if (class->gc_descr == GC_NO_DESCRIPTOR)
913 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
915 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
916 if (bitmap != default_bitmap)
922 * field_is_special_static:
923 * @fklass: The MonoClass to look up.
924 * @field: The MonoClassField describing the field.
926 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
927 * SPECIAL_STATIC_NONE otherwise.
930 field_is_special_static (MonoClass *fklass, MonoClassField *field)
932 MonoCustomAttrInfo *ainfo;
934 ainfo = mono_custom_attrs_from_field (fklass, field);
937 for (i = 0; i < ainfo->num_attrs; ++i) {
938 MonoClass *klass = ainfo->attrs [i].ctor->klass;
939 if (klass->image == mono_defaults.corlib) {
940 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
941 mono_custom_attrs_free (ainfo);
942 return SPECIAL_STATIC_THREAD;
944 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
945 mono_custom_attrs_free (ainfo);
946 return SPECIAL_STATIC_CONTEXT;
950 mono_custom_attrs_free (ainfo);
951 return SPECIAL_STATIC_NONE;
954 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
955 #define mix(a,b,c) { \
956 a -= c; a ^= rot(c, 4); c += b; \
957 b -= a; b ^= rot(a, 6); a += c; \
958 c -= b; c ^= rot(b, 8); b += a; \
959 a -= c; a ^= rot(c,16); c += b; \
960 b -= a; b ^= rot(a,19); a += c; \
961 c -= b; c ^= rot(b, 4); b += a; \
963 #define final(a,b,c) { \
964 c ^= b; c -= rot(b,14); \
965 a ^= c; a -= rot(c,11); \
966 b ^= a; b -= rot(a,25); \
967 c ^= b; c -= rot(b,16); \
968 a ^= c; a -= rot(c,4); \
969 b ^= a; b -= rot(a,14); \
970 c ^= b; c -= rot(b,24); \
974 mono_method_get_imt_slot (MonoMethod *method) {
975 MonoMethodSignature *sig;
977 guint32 *hashes_start, *hashes;
982 * We do this to simplify generic sharing. It will hurt
983 * performance in cases where a class implements two different
984 * instantiations of the same generic interface.
986 if (method->is_inflated)
987 method = ((MonoMethodInflated*)method)->declaring;
989 sig = mono_method_signature (method);
990 hashes_count = sig->param_count + 4;
991 hashes_start = malloc (hashes_count * sizeof (guint32));
992 hashes = hashes_start;
994 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
995 printf ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod\n",
996 method->klass->name_space, method->klass->name, method->name);
997 g_assert_not_reached ();
1000 /* Initialize hashes */
1001 hashes [0] = g_str_hash (method->klass->name);
1002 hashes [1] = g_str_hash (method->klass->name_space);
1003 hashes [2] = g_str_hash (method->name);
1004 hashes [3] = mono_metadata_type_hash (sig->ret);
1005 for (i = 0; i < sig->param_count; i++) {
1006 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1009 /* Setup internal state */
1010 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1012 /* Handle most of the hashes */
1013 while (hashes_count > 3) {
1022 /* Handle the last 3 hashes (all the case statements fall through) */
1023 switch (hashes_count) {
1024 case 3 : c += hashes [2];
1025 case 2 : b += hashes [1];
1026 case 1 : a += hashes [0];
1028 case 0: /* nothing left to add */
1032 free (hashes_start);
1033 /* Report the result */
1034 return c % MONO_IMT_SIZE;
1043 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1044 guint32 imt_slot = mono_method_get_imt_slot (method);
1045 MonoImtBuilderEntry *entry;
1047 if (slot_num >= 0 && imt_slot != slot_num) {
1048 /* we build just a single imt slot and this is not it */
1052 entry = malloc (sizeof (MonoImtBuilderEntry));
1053 entry->key = method;
1054 entry->value.vtable_slot = vtable_slot;
1055 entry->next = imt_builder [imt_slot];
1056 if (imt_builder [imt_slot] != NULL) {
1057 entry->children = imt_builder [imt_slot]->children + 1;
1058 if (entry->children == 1) {
1059 mono_stats.imt_slots_with_collisions++;
1060 *imt_collisions_bitmap |= (1 << imt_slot);
1063 entry->children = 0;
1064 mono_stats.imt_used_slots++;
1066 imt_builder [imt_slot] = entry;
1068 printf ("Added IMT slot for method (%p) %s.%s.%s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1069 method, method->klass->name_space, method->klass->name,
1070 method->name, imt_slot, vtable_slot, entry->children);
1076 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1078 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1082 e->method->klass->name_space,
1083 e->method->klass->name,
1086 printf (" * %s: NULL\n", message);
1092 compare_imt_builder_entries (const void *p1, const void *p2) {
1093 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1094 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1096 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1100 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1102 int count = end - start;
1103 int chunk_start = out_array->len;
1106 for (i = start; i < end; ++i) {
1107 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1108 item->key = sorted_array [i]->key;
1109 item->value = sorted_array [i]->value;
1110 item->is_equals = TRUE;
1112 item->check_target_idx = out_array->len + 1;
1114 item->check_target_idx = 0;
1115 g_ptr_array_add (out_array, item);
1118 int middle = start + count / 2;
1119 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1121 item->key = sorted_array [middle]->key;
1122 item->is_equals = FALSE;
1123 g_ptr_array_add (out_array, item);
1124 imt_emit_ir (sorted_array, start, middle, out_array);
1125 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1131 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1132 int number_of_entries = entries->children + 1;
1133 MonoImtBuilderEntry **sorted_array = malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1134 GPtrArray *result = g_ptr_array_new ();
1135 MonoImtBuilderEntry *current_entry;
1138 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1139 sorted_array [i] = current_entry;
1141 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1143 /*for (i = 0; i < number_of_entries; i++) {
1144 print_imt_entry (" sorted array:", sorted_array [i], i);
1147 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1149 free (sorted_array);
1154 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry) {
1155 if (imt_builder_entry != NULL) {
1156 if (imt_builder_entry->children == 0) {
1157 /* No collision, return the vtable slot contents */
1158 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1160 /* Collision, build the thunk */
1161 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1164 result = imt_thunk_builder (vtable, domain,
1165 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, NULL);
1166 for (i = 0; i < imt_ir->len; ++i)
1167 g_free (g_ptr_array_index (imt_ir, i));
1168 g_ptr_array_free (imt_ir, TRUE);
1178 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num) {
1181 guint32 imt_collisions_bitmap = 0;
1182 MonoImtBuilderEntry **imt_builder = calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1183 int method_count = 0;
1184 gboolean record_method_count_for_max_collisions = FALSE;
1187 printf ("Building IMT for class %s.%s\n", klass->name_space, klass->name);
1189 for (i = 0; i < klass->interface_offsets_count; ++i) {
1190 MonoClass *iface = klass->interfaces_packed [i];
1191 int interface_offset = klass->interface_offsets_packed [i];
1192 int method_slot_in_interface;
1193 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1194 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1195 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1198 if (extra_interfaces) {
1199 int interface_offset = klass->vtable_size;
1201 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1202 MonoClass* iface = list_item->data;
1203 int method_slot_in_interface;
1204 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1205 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1206 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1208 interface_offset += iface->method.count;
1211 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1212 /* overwrite the imt slot only if we're building all the entries or if
1213 * we're uilding this specific one
1215 if (slot_num < 0 || i == slot_num)
1216 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i]);
1218 printf ("initialize_imt_slot[%d]: %p\n", i, imt [i]);
1220 if (imt_builder [i] != NULL) {
1221 int methods_in_slot = imt_builder [i]->children + 1;
1222 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1223 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1224 record_method_count_for_max_collisions = TRUE;
1226 method_count += methods_in_slot;
1230 mono_stats.imt_number_of_methods += method_count;
1231 if (record_method_count_for_max_collisions) {
1232 mono_stats.imt_method_count_when_max_collisions = method_count;
1235 for (i = 0; i < MONO_IMT_SIZE; i++) {
1236 MonoImtBuilderEntry* entry = imt_builder [i];
1237 while (entry != NULL) {
1238 MonoImtBuilderEntry* next = entry->next;
1244 /* we OR the bitmap since we may build just a single imt slot at a time */
1245 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1249 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1250 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1253 static gpointer imt_trampoline = NULL;
1256 mono_install_imt_trampoline (gpointer tramp_code)
1258 imt_trampoline = tramp_code;
1261 static gpointer vtable_trampoline = NULL;
1264 mono_install_vtable_trampoline (gpointer tramp_code)
1266 vtable_trampoline = tramp_code;
1270 * mono_vtable_build_imt_slot:
1271 * @vtable: virtual object table struct
1272 * @imt_slot: slot in the IMT table
1274 * Fill the given @imt_slot in the IMT table of @vtable with
1275 * a trampoline or a thunk for the case of collisions.
1276 * This is part of the internal mono API.
1279 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1281 gpointer *imt = (gpointer*)vtable;
1282 imt -= MONO_IMT_SIZE;
1283 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1285 /* no support for extra interfaces: the proxy objects will need
1286 * to build the complete IMT
1287 * Update and heck needs to ahppen inside the proper domain lock, as all
1288 * the changes made to a MonoVTable.
1290 mono_domain_lock (vtable->domain);
1291 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1292 if (imt [imt_slot] == imt_trampoline)
1293 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1294 mono_domain_unlock (vtable->domain);
1299 * The first two free list entries both belong to the wait list: The
1300 * first entry is the pointer to the head of the list and the second
1301 * entry points to the last element. That way appending and removing
1302 * the first element are both O(1) operations.
1304 #define NUM_FREE_LISTS 12
1305 #define FIRST_FREE_LIST_SIZE 64
1306 #define MAX_WAIT_LENGTH 50
1307 #define THUNK_THRESHOLD 10
1310 * LOCKING: The domain lock must be held.
1313 init_thunk_free_lists (MonoDomain *domain)
1315 if (domain->thunk_free_lists)
1317 domain->thunk_free_lists = mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1321 list_index_for_size (int item_size)
1324 int size = FIRST_FREE_LIST_SIZE;
1326 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1335 * mono_method_alloc_generic_virtual_thunk:
1337 * @size: size in bytes
1339 * Allocs size bytes to be used for the code of a generic virtual
1340 * thunk. It's either allocated from the domain's code manager or
1341 * reused from a previously invalidated piece.
1343 * LOCKING: The domain lock must be held.
1346 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1348 static gboolean inited = FALSE;
1349 static int generic_virtual_thunks_size = 0;
1353 MonoThunkFreeList **l;
1355 init_thunk_free_lists (domain);
1357 size += sizeof (guint32);
1358 if (size < sizeof (MonoThunkFreeList))
1359 size = sizeof (MonoThunkFreeList);
1361 i = list_index_for_size (size);
1362 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1363 if ((*l)->size >= size) {
1364 MonoThunkFreeList *item = *l;
1366 return ((guint32*)item) + 1;
1370 /* no suitable item found - search lists of larger sizes */
1371 while (++i < NUM_FREE_LISTS) {
1372 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1375 g_assert (item->size > size);
1376 domain->thunk_free_lists [i] = item->next;
1377 return ((guint32*)item) + 1;
1380 /* still nothing found - allocate it */
1382 mono_counters_register ("Generic virtual thunk bytes",
1383 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1386 generic_virtual_thunks_size += size;
1388 p = mono_code_manager_reserve (domain->code_mp, size);
1395 * LOCKING: The domain lock must be held.
1398 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1401 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1403 init_thunk_free_lists (domain);
1405 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1406 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1407 int length = item->length;
1410 /* unlink the first item from the wait list */
1411 domain->thunk_free_lists [0] = item->next;
1412 domain->thunk_free_lists [0]->length = length - 1;
1414 i = list_index_for_size (item->size);
1416 /* put it in the free list */
1417 item->next = domain->thunk_free_lists [i];
1418 domain->thunk_free_lists [i] = item;
1422 if (domain->thunk_free_lists [1]) {
1423 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1424 domain->thunk_free_lists [0]->length++;
1426 g_assert (!domain->thunk_free_lists [0]);
1428 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1429 domain->thunk_free_lists [0]->length = 1;
1433 typedef struct _GenericVirtualCase {
1434 MonoGenericInst *inst;
1437 struct _GenericVirtualCase *next;
1438 } GenericVirtualCase;
1441 * mono_method_add_generic_virtual_invocation:
1443 * @vtable_slot: pointer to the vtable slot
1444 * @method_inst: the method's method_inst
1445 * @code: the method's code
1447 * Registers a call via unmanaged code to a generic virtual method
1448 * instantiation. If the number of calls reaches a threshold
1449 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1450 * virtual method thunk.
1453 mono_method_add_generic_virtual_invocation (MonoDomain *domain, gpointer *vtable_slot,
1454 MonoGenericInst *method_inst, gpointer code)
1456 static gboolean inited = FALSE;
1457 static int num_added = 0;
1459 GenericVirtualCase *gvc, *list;
1460 MonoImtBuilderEntry *entries;
1464 mono_domain_lock (domain);
1465 if (!domain->generic_virtual_cases)
1466 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1468 /* Check whether the case was already added */
1469 gvc = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1471 if (gvc->inst == method_inst)
1476 /* If not found, make a new one */
1478 gvc = mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1479 gvc->inst = method_inst;
1482 gvc->next = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1484 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1487 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1493 if (++gvc->count < THUNK_THRESHOLD) {
1494 mono_domain_unlock (domain);
1499 for (list = gvc; list; list = list->next) {
1500 MonoImtBuilderEntry *entry;
1502 if (list->count < THUNK_THRESHOLD)
1505 entry = g_new0 (MonoImtBuilderEntry, 1);
1506 entry->key = list->inst;
1507 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1509 entry->children = entries->children + 1;
1510 entry->next = entries;
1514 sorted = imt_sort_slot_entries (entries);
1516 if (*vtable_slot != vtable_trampoline)
1517 invalidate_generic_virtual_thunk (domain, *vtable_slot);
1519 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1522 mono_domain_unlock (domain);
1525 MonoImtBuilderEntry *next = entries->next;
1530 for (i = 0; i < sorted->len; ++i)
1531 g_free (g_ptr_array_index (sorted, i));
1532 g_ptr_array_free (sorted, TRUE);
1535 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class);
1538 * mono_class_vtable:
1539 * @domain: the application domain
1540 * @class: the class to initialize
1542 * VTables are domain specific because we create domain specific code, and
1543 * they contain the domain specific static class data.
1544 * On failure, NULL is returned, and class->exception_type is set.
1547 mono_class_vtable (MonoDomain *domain, MonoClass *class)
1549 MonoClassRuntimeInfo *runtime_info;
1553 /* this check can be inlined in jitted code, too */
1554 runtime_info = class->runtime_info;
1555 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1556 return runtime_info->domain_vtables [domain->domain_id];
1557 if (class->exception_type)
1559 return mono_class_create_runtime_vtable (domain, class);
1563 * mono_class_try_get_vtable:
1564 * @domain: the application domain
1565 * @class: the class to initialize
1567 * This function tries to get the associated vtable from @class if
1568 * it was already created.
1571 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *class)
1573 MonoClassRuntimeInfo *runtime_info;
1577 runtime_info = class->runtime_info;
1578 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1579 return runtime_info->domain_vtables [domain->domain_id];
1584 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class)
1587 MonoClassRuntimeInfo *runtime_info, *old_info;
1588 MonoClassField *field;
1591 int imt_table_bytes = 0;
1592 guint32 vtable_size, class_size;
1595 gpointer *interface_offsets;
1597 mono_domain_lock (domain);
1598 runtime_info = class->runtime_info;
1599 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1600 mono_domain_unlock (domain);
1601 return runtime_info->domain_vtables [domain->domain_id];
1603 if (!class->inited || class->exception_type) {
1604 if (!mono_class_init (class) || class->exception_type){
1606 mono_domain_unlock (domain);
1607 exc = mono_class_get_exception_for_failure (class);
1609 mono_raise_exception (exc);
1613 mono_class_init (class);
1616 * For some classes, mono_class_init () already computed class->vtable_size, and
1617 * that is all that is needed because of the vtable trampolines.
1619 if (!class->vtable_size)
1620 mono_class_setup_vtable (class);
1622 if (class->exception_type) {
1623 mono_domain_unlock (domain);
1628 vtable_size = sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
1629 if (class->interface_offsets_count) {
1630 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1631 vtable_size += sizeof (gpointer) * (MONO_IMT_SIZE);
1632 mono_stats.imt_number_of_tables++;
1633 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
1636 vtable_size = sizeof (gpointer) * (class->max_interface_id + 1) +
1637 sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
1640 mono_stats.used_class_count++;
1641 mono_stats.class_vtable_size += vtable_size;
1642 interface_offsets = mono_domain_alloc0 (domain, vtable_size);
1645 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1647 vt = (MonoVTable*) (interface_offsets + class->max_interface_id + 1);
1649 vt->rank = class->rank;
1650 vt->domain = domain;
1652 mono_class_compute_gc_descriptor (class);
1654 * We can't use typed allocation in the non-root domains, since the
1655 * collector needs the GC descriptor stored in the vtable even after
1656 * the mempool containing the vtable is destroyed when the domain is
1657 * unloaded. An alternative might be to allocate vtables in the GC
1658 * heap, but this does not seem to work (it leads to crashes inside
1659 * libgc). If that approach is tried, two gc descriptors need to be
1660 * allocated for each class: one for the root domain, and one for all
1661 * other domains. The second descriptor should contain a bit for the
1662 * vtable field in MonoObject, since we can no longer assume the
1663 * vtable is reachable by other roots after the appdomain is unloaded.
1665 #ifdef HAVE_BOEHM_GC
1666 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1667 vt->gc_descr = GC_NO_DESCRIPTOR;
1670 vt->gc_descr = class->gc_descr;
1672 if ((class_size = mono_class_data_size (class))) {
1673 if (class->has_static_refs) {
1674 gpointer statics_gc_descr;
1676 gsize default_bitmap [4] = {0};
1679 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1680 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
1681 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set? max_set + 1: 0);
1682 vt->data = mono_gc_alloc_fixed (class_size, statics_gc_descr);
1683 mono_domain_add_class_static_data (domain, class, vt->data, NULL);
1684 if (bitmap != default_bitmap)
1687 vt->data = mono_domain_alloc0 (domain, class_size);
1689 mono_stats.class_static_data_size += class_size;
1694 while ((field = mono_class_get_fields (class, &iter))) {
1695 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1697 if (mono_field_is_deleted (field))
1699 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1700 gint32 special_static = class->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (class, field);
1701 if (special_static != SPECIAL_STATIC_NONE) {
1702 guint32 size, offset;
1704 size = mono_type_size (field->type, &align);
1705 offset = mono_alloc_special_static_data (special_static, size, align);
1706 if (!domain->special_static_fields)
1707 domain->special_static_fields = g_hash_table_new (NULL, NULL);
1708 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
1712 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
1713 MonoClass *fklass = mono_class_from_mono_type (field->type);
1714 const char *data = mono_field_get_data (field);
1716 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
1717 t = (char*)vt->data + field->offset;
1718 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
1721 if (fklass->valuetype) {
1722 memcpy (t, data, mono_class_value_size (fklass, NULL));
1724 /* it's a pointer type: add check */
1725 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
1732 vt->max_interface_id = class->max_interface_id;
1733 vt->interface_bitmap = class->interface_bitmap;
1735 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
1736 // class->name, class->interface_offsets_count);
1738 if (! ARCH_USE_IMT) {
1739 /* initialize interface offsets */
1740 for (i = 0; i < class->interface_offsets_count; ++i) {
1741 int interface_id = class->interfaces_packed [i]->interface_id;
1742 int slot = class->interface_offsets_packed [i];
1743 interface_offsets [class->max_interface_id - interface_id] = &(vt->vtable [slot]);
1747 /* FIXME: class_vtable_hash is basically obsolete now: remove as soon
1748 * as we change the code in appdomain.c to invalidate vtables by
1749 * looking at the possible MonoClasses created for the domain.
1751 g_hash_table_insert (domain->class_vtable_hash, class, vt);
1752 /* class->runtime_info is protected by the loader lock, both when
1753 * it it enlarged and when it is stored info.
1755 mono_loader_lock ();
1756 old_info = class->runtime_info;
1757 if (old_info && old_info->max_domain >= domain->domain_id) {
1758 /* someone already created a large enough runtime info */
1759 mono_memory_barrier ();
1760 old_info->domain_vtables [domain->domain_id] = vt;
1762 int new_size = domain->domain_id;
1764 new_size = MAX (new_size, old_info->max_domain);
1766 /* make the new size a power of two */
1768 while (new_size > i)
1771 /* this is a bounded memory retention issue: may want to
1772 * handle it differently when we'll have a rcu-like system.
1774 runtime_info = mono_image_alloc0 (class->image, sizeof (MonoClassRuntimeInfo) + new_size * sizeof (gpointer));
1775 runtime_info->max_domain = new_size - 1;
1776 /* copy the stuff from the older info */
1778 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
1780 runtime_info->domain_vtables [domain->domain_id] = vt;
1782 mono_memory_barrier ();
1783 class->runtime_info = runtime_info;
1785 mono_loader_unlock ();
1787 /* Initialize vtable */
1788 if (vtable_trampoline) {
1789 // This also covers the AOT case
1790 for (i = 0; i < class->vtable_size; ++i) {
1791 vt->vtable [i] = vtable_trampoline;
1794 mono_class_setup_vtable (class);
1796 for (i = 0; i < class->vtable_size; ++i) {
1799 if ((cm = class->vtable [i])) {
1800 if (mono_method_signature (cm)->generic_param_count)
1801 /* FIXME: Why is this needed ? */
1802 vt->vtable [i] = cm;
1804 vt->vtable [i] = vtable_trampoline? vtable_trampoline: arch_create_jit_trampoline (cm);
1809 if (ARCH_USE_IMT && imt_table_bytes) {
1810 /* Now that the vtable is full, we can actually fill up the IMT */
1811 if (imt_trampoline) {
1812 /* lazy construction of the IMT entries enabled */
1813 for (i = 0; i < MONO_IMT_SIZE; ++i)
1814 interface_offsets [i] = imt_trampoline;
1816 build_imt (class, vt, domain, interface_offsets, NULL);
1820 mono_domain_unlock (domain);
1822 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
1823 if (mono_is_security_manager_active () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND)) {
1824 MonoException *exc = mono_class_get_exception_for_failure (class);
1826 mono_raise_exception (exc);
1829 /* make sure the parent is initialized */
1831 mono_class_vtable (domain, class->parent);
1833 vt->type = mono_type_get_object (domain, &class->byval_arg);
1834 if (class->contextbound)
1843 * mono_class_proxy_vtable:
1844 * @domain: the application domain
1845 * @remove_class: the remote class
1847 * Creates a vtable for transparent proxies. It is basically
1848 * a copy of the real vtable of the class wrapped in @remote_class,
1849 * but all function pointers invoke the remoting functions, and
1850 * vtable->klass points to the transparent proxy class, and not to @class.
1853 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
1855 MonoVTable *vt, *pvt;
1856 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
1858 GSList *extra_interfaces = NULL;
1859 MonoClass *class = remote_class->proxy_class;
1860 gpointer *interface_offsets;
1862 vt = mono_class_vtable (domain, class);
1863 max_interface_id = vt->max_interface_id;
1865 /* Calculate vtable space for extra interfaces */
1866 for (j = 0; j < remote_class->interface_count; j++) {
1867 MonoClass* iclass = remote_class->interfaces[j];
1871 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
1872 continue; /* interface implemented by the class */
1873 if (g_slist_find (extra_interfaces, iclass))
1876 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
1878 method_count = mono_class_num_methods (iclass);
1880 ifaces = mono_class_get_implemented_interfaces (iclass);
1882 for (i = 0; i < ifaces->len; ++i) {
1883 MonoClass *ic = g_ptr_array_index (ifaces, i);
1884 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
1885 continue; /* interface implemented by the class */
1886 if (g_slist_find (extra_interfaces, ic))
1888 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
1889 method_count += mono_class_num_methods (ic);
1891 g_ptr_array_free (ifaces, TRUE);
1894 extra_interface_vtsize += method_count * sizeof (gpointer);
1895 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
1899 mono_stats.imt_number_of_tables++;
1900 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
1901 vtsize = sizeof (gpointer) * (MONO_IMT_SIZE) +
1902 sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
1904 vtsize = sizeof (gpointer) * (max_interface_id + 1) +
1905 sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
1908 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
1910 interface_offsets = mono_domain_alloc0 (domain, vtsize + extra_interface_vtsize);
1912 pvt = (MonoVTable*) (interface_offsets + MONO_IMT_SIZE);
1914 pvt = (MonoVTable*) (interface_offsets + max_interface_id + 1);
1915 memcpy (pvt, vt, sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer));
1917 pvt->klass = mono_defaults.transparent_proxy_class;
1918 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
1919 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
1921 /* initialize vtable */
1922 mono_class_setup_vtable (class);
1923 for (i = 0; i < class->vtable_size; ++i) {
1926 if ((cm = class->vtable [i]))
1927 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
1929 pvt->vtable [i] = NULL;
1932 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
1933 /* create trampolines for abstract methods */
1934 for (k = class; k; k = k->parent) {
1936 gpointer iter = NULL;
1937 while ((m = mono_class_get_methods (k, &iter)))
1938 if (!pvt->vtable [m->slot])
1939 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
1943 pvt->max_interface_id = max_interface_id;
1944 pvt->interface_bitmap = mono_domain_alloc0 (domain, sizeof (guint8) * (max_interface_id/8 + 1 ));
1946 if (! ARCH_USE_IMT) {
1947 /* initialize interface offsets */
1948 for (i = 0; i < class->interface_offsets_count; ++i) {
1949 int interface_id = class->interfaces_packed [i]->interface_id;
1950 int slot = class->interface_offsets_packed [i];
1951 interface_offsets [class->max_interface_id - interface_id] = &(pvt->vtable [slot]);
1954 for (i = 0; i < class->interface_offsets_count; ++i) {
1955 int interface_id = class->interfaces_packed [i]->interface_id;
1956 pvt->interface_bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
1959 if (extra_interfaces) {
1960 int slot = class->vtable_size;
1966 /* Create trampolines for the methods of the interfaces */
1967 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1968 interf = list_item->data;
1970 if (! ARCH_USE_IMT) {
1971 interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
1973 pvt->interface_bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
1977 while ((cm = mono_class_get_methods (interf, &iter)))
1978 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
1980 slot += mono_class_num_methods (interf);
1982 if (! ARCH_USE_IMT) {
1983 g_slist_free (extra_interfaces);
1988 /* Now that the vtable is full, we can actually fill up the IMT */
1989 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
1990 if (extra_interfaces) {
1991 g_slist_free (extra_interfaces);
1999 * mono_class_field_is_special_static:
2001 * Returns whether @field is a thread/context static field.
2004 mono_class_field_is_special_static (MonoClassField *field)
2006 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2008 if (mono_field_is_deleted (field))
2010 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2011 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2018 * mono_class_has_special_static_fields:
2020 * Returns whenever @klass has any thread/context static fields.
2023 mono_class_has_special_static_fields (MonoClass *klass)
2025 MonoClassField *field;
2029 while ((field = mono_class_get_fields (klass, &iter))) {
2030 g_assert (field->parent == klass);
2031 if (mono_class_field_is_special_static (field))
2039 * create_remote_class_key:
2040 * Creates an array of pointers that can be used as a hash key for a remote class.
2041 * The first element of the array is the number of pointers.
2044 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2049 if (remote_class == NULL) {
2050 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2051 key = g_malloc (sizeof(gpointer) * 3);
2052 key [0] = GINT_TO_POINTER (2);
2053 key [1] = mono_defaults.marshalbyrefobject_class;
2054 key [2] = extra_class;
2056 key = g_malloc (sizeof(gpointer) * 2);
2057 key [0] = GINT_TO_POINTER (1);
2058 key [1] = extra_class;
2061 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2062 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2063 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2064 key [1] = remote_class->proxy_class;
2066 // Keep the list of interfaces sorted
2067 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2068 if (extra_class && remote_class->interfaces [i] > extra_class) {
2069 key [j++] = extra_class;
2072 key [j] = remote_class->interfaces [i];
2075 key [j] = extra_class;
2077 // Replace the old class. The interface list is the same
2078 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2079 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2080 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2081 for (i = 0; i < remote_class->interface_count; i++)
2082 key [2 + i] = remote_class->interfaces [i];
2090 * copy_remote_class_key:
2092 * Make a copy of KEY in the domain and return the copy.
2095 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2097 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2098 gpointer *mp_key = mono_domain_alloc (domain, key_size);
2100 memcpy (mp_key, key, key_size);
2106 * mono_remote_class:
2107 * @domain: the application domain
2108 * @class_name: name of the remote class
2110 * Creates and initializes a MonoRemoteClass object for a remote type.
2114 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2116 MonoRemoteClass *rc;
2117 gpointer* key, *mp_key;
2119 key = create_remote_class_key (NULL, proxy_class);
2121 mono_domain_lock (domain);
2122 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2126 mono_domain_unlock (domain);
2130 mp_key = copy_remote_class_key (domain, key);
2134 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2135 rc = mono_domain_alloc (domain, sizeof(MonoRemoteClass) + sizeof(MonoClass*));
2136 rc->interface_count = 1;
2137 rc->interfaces [0] = proxy_class;
2138 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2140 rc = mono_domain_alloc (domain, sizeof(MonoRemoteClass));
2141 rc->interface_count = 0;
2142 rc->proxy_class = proxy_class;
2145 rc->default_vtable = NULL;
2146 rc->xdomain_vtable = NULL;
2147 rc->proxy_class_name = mono_string_to_utf8_mp (domain->mp, class_name);
2148 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2150 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2152 mono_domain_unlock (domain);
2157 * clone_remote_class:
2158 * Creates a copy of the remote_class, adding the provided class or interface
2160 static MonoRemoteClass*
2161 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2163 MonoRemoteClass *rc;
2164 gpointer* key, *mp_key;
2166 key = create_remote_class_key (remote_class, extra_class);
2167 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2173 mp_key = copy_remote_class_key (domain, key);
2177 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2179 rc = mono_domain_alloc (domain, sizeof(MonoRemoteClass) + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2180 rc->proxy_class = remote_class->proxy_class;
2181 rc->interface_count = remote_class->interface_count + 1;
2183 // Keep the list of interfaces sorted, since the hash key of
2184 // the remote class depends on this
2185 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2186 if (remote_class->interfaces [i] > extra_class && i == j)
2187 rc->interfaces [j++] = extra_class;
2188 rc->interfaces [j] = remote_class->interfaces [i];
2191 rc->interfaces [j] = extra_class;
2193 // Replace the old class. The interface array is the same
2194 rc = mono_domain_alloc (domain, sizeof(MonoRemoteClass) + sizeof(MonoClass*) * remote_class->interface_count);
2195 rc->proxy_class = extra_class;
2196 rc->interface_count = remote_class->interface_count;
2197 if (rc->interface_count > 0)
2198 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2201 rc->default_vtable = NULL;
2202 rc->xdomain_vtable = NULL;
2203 rc->proxy_class_name = remote_class->proxy_class_name;
2205 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2211 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2213 mono_domain_lock (domain);
2214 if (rp->target_domain_id != -1) {
2215 if (remote_class->xdomain_vtable == NULL)
2216 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2217 mono_domain_unlock (domain);
2218 return remote_class->xdomain_vtable;
2220 if (remote_class->default_vtable == NULL) {
2223 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2224 klass = mono_class_from_mono_type (type);
2225 if ((klass->is_com_object || (mono_defaults.com_object_class && klass == mono_defaults.com_object_class)) && !mono_class_vtable (mono_domain_get (), klass)->remote)
2226 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2228 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2231 mono_domain_unlock (domain);
2232 return remote_class->default_vtable;
2236 * mono_upgrade_remote_class:
2237 * @domain: the application domain
2238 * @tproxy: the proxy whose remote class has to be upgraded.
2239 * @klass: class to which the remote class can be casted.
2241 * Updates the vtable of the remote class by adding the necessary method slots
2242 * and interface offsets so it can be safely casted to klass. klass can be a
2243 * class or an interface.
2246 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2248 MonoTransparentProxy *tproxy;
2249 MonoRemoteClass *remote_class;
2250 gboolean redo_vtable;
2252 mono_domain_lock (domain);
2254 tproxy = (MonoTransparentProxy*) proxy_object;
2255 remote_class = tproxy->remote_class;
2257 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2260 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2261 if (remote_class->interfaces [i] == klass)
2262 redo_vtable = FALSE;
2265 redo_vtable = (remote_class->proxy_class != klass);
2269 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2270 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2273 mono_domain_unlock (domain);
2278 * mono_object_get_virtual_method:
2279 * @obj: object to operate on.
2282 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2283 * the instance of a callvirt of method.
2286 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2289 MonoMethod **vtable;
2291 MonoMethod *res = NULL;
2293 klass = mono_object_class (obj);
2294 if (klass == mono_defaults.transparent_proxy_class) {
2295 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2301 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2304 mono_class_setup_vtable (klass);
2305 vtable = klass->vtable;
2307 if (method->slot == -1) {
2308 /* method->slot might not be set for instances of generic methods */
2309 if (method->is_inflated) {
2310 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2311 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2314 g_assert_not_reached ();
2318 /* check method->slot is a valid index: perform isinstance? */
2319 if (method->slot != -1) {
2320 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2322 res = vtable [mono_class_interface_offset (klass, method->klass) + method->slot];
2324 res = vtable [method->slot];
2329 /* It may be an interface, abstract class method or generic method */
2330 if (!res || mono_method_signature (res)->generic_param_count)
2333 /* generic methods demand invoke_with_check */
2334 if (mono_method_signature (res)->generic_param_count)
2335 res = mono_marshal_get_remoting_invoke_with_check (res);
2337 res = mono_marshal_get_remoting_invoke (res);
2339 if (method->is_inflated && !res->is_inflated) {
2340 /* Have to inflate the result */
2341 res = mono_class_inflate_generic_method (res, &((MonoMethodInflated*)method)->context);
2351 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2353 g_error ("runtime invoke called on uninitialized runtime");
2357 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2360 * mono_runtime_invoke:
2361 * @method: method to invoke
2362 * @obJ: object instance
2363 * @params: arguments to the method
2364 * @exc: exception information.
2366 * Invokes the method represented by @method on the object @obj.
2368 * obj is the 'this' pointer, it should be NULL for static
2369 * methods, a MonoObject* for object instances and a pointer to
2370 * the value type for value types.
2372 * The params array contains the arguments to the method with the
2373 * same convention: MonoObject* pointers for object instances and
2374 * pointers to the value type otherwise.
2376 * From unmanaged code you'll usually use the
2377 * mono_runtime_invoke() variant.
2379 * Note that this function doesn't handle virtual methods for
2380 * you, it will exec the exact method you pass: we still need to
2381 * expose a function to lookup the derived class implementation
2382 * of a virtual method (there are examples of this in the code,
2385 * You can pass NULL as the exc argument if you don't want to
2386 * catch exceptions, otherwise, *exc will be set to the exception
2387 * thrown, if any. if an exception is thrown, you can't use the
2388 * MonoObject* result from the function.
2390 * If the method returns a value type, it is boxed in an object
2394 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2396 if (mono_runtime_get_no_exec ())
2397 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2399 return default_mono_runtime_invoke (method, obj, params, exc);
2403 * mono_method_get_unmanaged_thunk:
2404 * @method: method to generate a thunk for.
2406 * Returns an unmanaged->managed thunk that can be used to call
2407 * a managed method directly from C.
2409 * The thunk's C signature closely matches the managed signature:
2411 * C#: public bool Equals (object obj);
2412 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2413 * MonoObject*, MonoException**);
2415 * The 1st ("this") parameter must not be used with static methods:
2417 * C#: public static bool ReferenceEquals (object a, object b);
2418 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2421 * The last argument must be a non-null pointer of a MonoException* pointer.
2422 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2423 * exception has been thrown in managed code. Otherwise it will point
2424 * to the MonoException* caught by the thunk. In this case, the result of
2425 * the thunk is undefined:
2427 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2428 * MonoException *ex = NULL;
2429 * Equals func = mono_method_get_unmanaged_thunk (method);
2430 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2432 * // handle exception
2435 * The calling convention of the thunk matches the platform's default
2436 * convention. This means that under Windows, C declarations must
2437 * contain the __stdcall attribute:
2439 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2440 * MonoObject*, MonoException**);
2444 * Value type arguments and return values are treated as they were objects:
2446 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2447 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2449 * Arguments must be properly boxed upon trunk's invocation, while return
2450 * values must be unboxed.
2453 mono_method_get_unmanaged_thunk (MonoMethod *method)
2455 method = mono_marshal_get_thunk_invoke_wrapper (method);
2456 return mono_compile_method (method);
2460 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
2464 gpointer *p = (gpointer*)dest;
2471 case MONO_TYPE_BOOLEAN:
2473 case MONO_TYPE_U1: {
2474 guint8 *p = (guint8*)dest;
2475 *p = value ? *(guint8*)value : 0;
2480 case MONO_TYPE_CHAR: {
2481 guint16 *p = (guint16*)dest;
2482 *p = value ? *(guint16*)value : 0;
2485 #if SIZEOF_VOID_P == 4
2490 case MONO_TYPE_U4: {
2491 gint32 *p = (gint32*)dest;
2492 *p = value ? *(gint32*)value : 0;
2495 #if SIZEOF_VOID_P == 8
2500 case MONO_TYPE_U8: {
2501 gint64 *p = (gint64*)dest;
2502 *p = value ? *(gint64*)value : 0;
2505 case MONO_TYPE_R4: {
2506 float *p = (float*)dest;
2507 *p = value ? *(float*)value : 0;
2510 case MONO_TYPE_R8: {
2511 double *p = (double*)dest;
2512 *p = value ? *(double*)value : 0;
2515 case MONO_TYPE_STRING:
2516 case MONO_TYPE_SZARRAY:
2517 case MONO_TYPE_CLASS:
2518 case MONO_TYPE_OBJECT:
2519 case MONO_TYPE_ARRAY:
2520 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2522 case MONO_TYPE_FNPTR:
2523 case MONO_TYPE_PTR: {
2524 gpointer *p = (gpointer*)dest;
2525 *p = deref_pointer? *(gpointer*)value: value;
2528 case MONO_TYPE_VALUETYPE:
2529 /* note that 't' and 'type->type' can be different */
2530 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
2531 t = type->data.klass->enum_basetype->type;
2535 size = mono_class_value_size (mono_class_from_mono_type (type), NULL);
2537 memset (dest, 0, size);
2539 memcpy (dest, value, size);
2542 case MONO_TYPE_GENERICINST:
2543 t = type->data.generic_class->container_class->byval_arg.type;
2546 g_warning ("got type %x", type->type);
2547 g_assert_not_reached ();
2552 * mono_field_set_value:
2553 * @obj: Instance object
2554 * @field: MonoClassField describing the field to set
2555 * @value: The value to be set
2557 * Sets the value of the field described by @field in the object instance @obj
2558 * to the value passed in @value. This method should only be used for instance
2559 * fields. For static fields, use mono_field_static_set_value.
2561 * The value must be on the native format of the field type.
2564 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
2568 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2570 dest = (char*)obj + field->offset;
2571 set_value (field->type, dest, value, FALSE);
2575 * mono_field_static_set_value:
2576 * @field: MonoClassField describing the field to set
2577 * @value: The value to be set
2579 * Sets the value of the static field described by @field
2580 * to the value passed in @value.
2582 * The value must be on the native format of the field type.
2585 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
2589 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2590 /* you cant set a constant! */
2591 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
2593 dest = (char*)vt->data + field->offset;
2594 set_value (field->type, dest, value, FALSE);
2597 /* Used by the debugger */
2599 mono_vtable_get_static_field_data (MonoVTable *vt)
2605 * mono_field_get_value:
2606 * @obj: Object instance
2607 * @field: MonoClassField describing the field to fetch information from
2608 * @value: pointer to the location where the value will be stored
2610 * Use this routine to get the value of the field @field in the object
2613 * The pointer provided by value must be of the field type, for reference
2614 * types this is a MonoObject*, for value types its the actual pointer to
2619 * mono_field_get_value (obj, int_field, &i);
2622 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
2626 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2628 src = (char*)obj + field->offset;
2629 set_value (field->type, value, src, TRUE);
2633 * mono_field_get_value_object:
2634 * @domain: domain where the object will be created (if boxing)
2635 * @field: MonoClassField describing the field to fetch information from
2636 * @obj: The object instance for the field.
2638 * Returns: a new MonoObject with the value from the given field. If the
2639 * field represents a value type, the value is boxed.
2643 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
2647 MonoVTable *vtable = NULL;
2649 gboolean is_static = FALSE;
2650 gboolean is_ref = FALSE;
2652 switch (field->type->type) {
2653 case MONO_TYPE_STRING:
2654 case MONO_TYPE_OBJECT:
2655 case MONO_TYPE_CLASS:
2656 case MONO_TYPE_ARRAY:
2657 case MONO_TYPE_SZARRAY:
2662 case MONO_TYPE_BOOLEAN:
2665 case MONO_TYPE_CHAR:
2674 case MONO_TYPE_VALUETYPE:
2675 is_ref = field->type->byref;
2677 case MONO_TYPE_GENERICINST:
2678 is_ref = !field->type->data.generic_class->container_class->valuetype;
2681 g_error ("type 0x%x not handled in "
2682 "mono_field_get_value_object", field->type->type);
2686 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
2688 vtable = mono_class_vtable (domain, field->parent);
2689 if (!vtable->initialized)
2690 mono_runtime_class_init (vtable);
2695 mono_field_static_get_value (vtable, field, &o);
2697 mono_field_get_value (obj, field, &o);
2702 /* boxed value type */
2703 klass = mono_class_from_mono_type (field->type);
2704 o = mono_object_new (domain, klass);
2705 v = ((gchar *) o) + sizeof (MonoObject);
2707 mono_field_static_get_value (vtable, field, v);
2709 mono_field_get_value (obj, field, v);
2716 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
2719 const char *p = blob;
2720 mono_metadata_decode_blob_size (p, &p);
2723 case MONO_TYPE_BOOLEAN:
2726 *(guint8 *) value = *p;
2728 case MONO_TYPE_CHAR:
2731 *(guint16*) value = read16 (p);
2735 *(guint32*) value = read32 (p);
2739 *(guint64*) value = read64 (p);
2742 readr4 (p, (float*) value);
2745 readr8 (p, (double*) value);
2747 case MONO_TYPE_STRING:
2748 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
2750 case MONO_TYPE_CLASS:
2751 *(gpointer*) value = NULL;
2755 g_warning ("type 0x%02x should not be in constant table", type);
2761 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
2763 MonoTypeEnum def_type;
2766 data = mono_class_get_field_default_value (field, &def_type);
2767 mono_get_constant_value_from_blob (domain, def_type, data, value);
2771 * mono_field_static_get_value:
2772 * @vt: vtable to the object
2773 * @field: MonoClassField describing the field to fetch information from
2774 * @value: where the value is returned
2776 * Use this routine to get the value of the static field @field value.
2778 * The pointer provided by value must be of the field type, for reference
2779 * types this is a MonoObject*, for value types its the actual pointer to
2784 * mono_field_static_get_value (vt, int_field, &i);
2787 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
2791 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2793 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
2794 get_default_field_value (vt->domain, field, value);
2798 src = (char*)vt->data + field->offset;
2799 set_value (field->type, value, src, TRUE);
2803 * mono_property_set_value:
2804 * @prop: MonoProperty to set
2805 * @obj: instance object on which to act
2806 * @params: parameters to pass to the propery
2807 * @exc: optional exception
2809 * Invokes the property's set method with the given arguments on the
2810 * object instance obj (or NULL for static properties).
2812 * You can pass NULL as the exc argument if you don't want to
2813 * catch exceptions, otherwise, *exc will be set to the exception
2814 * thrown, if any. if an exception is thrown, you can't use the
2815 * MonoObject* result from the function.
2818 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
2820 default_mono_runtime_invoke (prop->set, obj, params, exc);
2824 * mono_property_get_value:
2825 * @prop: MonoProperty to fetch
2826 * @obj: instance object on which to act
2827 * @params: parameters to pass to the propery
2828 * @exc: optional exception
2830 * Invokes the property's get method with the given arguments on the
2831 * object instance obj (or NULL for static properties).
2833 * You can pass NULL as the exc argument if you don't want to
2834 * catch exceptions, otherwise, *exc will be set to the exception
2835 * thrown, if any. if an exception is thrown, you can't use the
2836 * MonoObject* result from the function.
2838 * Returns: the value from invoking the get method on the property.
2841 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
2843 return default_mono_runtime_invoke (prop->get, obj, params, exc);
2847 * mono_nullable_init:
2848 * @buf: The nullable structure to initialize.
2849 * @value: the value to initialize from
2850 * @klass: the type for the object
2852 * Initialize the nullable structure pointed to by @buf from @value which
2853 * should be a boxed value type. The size of @buf should be able to hold
2854 * as much data as the @klass->instance_size (which is the number of bytes
2855 * that will be copies).
2857 * Since Nullables have variable structure, we can not define a C
2858 * structure for them.
2861 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
2863 MonoClass *param_class = klass->cast_class;
2865 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
2866 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
2868 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
2870 memcpy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
2872 memset (buf + klass->fields [0].offset - sizeof (MonoObject), 0, mono_class_value_size (param_class, NULL));
2876 * mono_nullable_box:
2877 * @buf: The buffer representing the data to be boxed
2878 * @klass: the type to box it as.
2880 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
2884 mono_nullable_box (guint8 *buf, MonoClass *klass)
2886 MonoClass *param_class = klass->cast_class;
2888 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
2889 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
2891 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
2892 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
2893 memcpy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
2901 * mono_get_delegate_invoke:
2902 * @klass: The delegate class
2904 * Returns: the MonoMethod for the "Invoke" method in the delegate klass
2907 mono_get_delegate_invoke (MonoClass *klass)
2911 im = mono_class_get_method_from_name (klass, "Invoke", -1);
2918 * mono_runtime_delegate_invoke:
2919 * @delegate: pointer to a delegate object.
2920 * @params: parameters for the delegate.
2921 * @exc: Pointer to the exception result.
2923 * Invokes the delegate method @delegate with the parameters provided.
2925 * You can pass NULL as the exc argument if you don't want to
2926 * catch exceptions, otherwise, *exc will be set to the exception
2927 * thrown, if any. if an exception is thrown, you can't use the
2928 * MonoObject* result from the function.
2931 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
2935 im = mono_get_delegate_invoke (delegate->vtable->klass);
2938 return mono_runtime_invoke (im, delegate, params, exc);
2941 static char **main_args = NULL;
2942 static int num_main_args;
2945 * mono_runtime_get_main_args:
2947 * Returns: a MonoArray with the arguments passed to the main program
2950 mono_runtime_get_main_args (void)
2954 MonoDomain *domain = mono_domain_get ();
2959 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
2961 for (i = 0; i < num_main_args; ++i)
2962 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
2968 fire_process_exit_event (void)
2970 MonoClassField *field;
2971 MonoDomain *domain = mono_domain_get ();
2973 MonoObject *delegate, *exc;
2975 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "ProcessExit");
2978 if (domain != mono_get_root_domain ())
2981 delegate = *(MonoObject **)(((char *)domain->domain) + field->offset);
2982 if (delegate == NULL)
2987 mono_runtime_delegate_invoke (delegate, pa, &exc);
2991 * mono_runtime_run_main:
2992 * @method: the method to start the application with (usually Main)
2993 * @argc: number of arguments from the command line
2994 * @argv: array of strings from the command line
2995 * @exc: excetption results
2997 * Execute a standard Main() method (argc/argv contains the
2998 * executable name). This method also sets the command line argument value
2999 * needed by System.Environment.
3004 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3008 MonoArray *args = NULL;
3009 MonoDomain *domain = mono_domain_get ();
3010 gchar *utf8_fullpath;
3013 g_assert (method != NULL);
3015 mono_thread_set_main (mono_thread_current ());
3017 main_args = g_new0 (char*, argc);
3018 num_main_args = argc;
3020 if (!g_path_is_absolute (argv [0])) {
3021 gchar *basename = g_path_get_basename (argv [0]);
3022 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3026 utf8_fullpath = mono_utf8_from_external (fullpath);
3027 if(utf8_fullpath == NULL) {
3028 /* Printing the arg text will cause glib to
3029 * whinge about "Invalid UTF-8", but at least
3030 * its relevant, and shows the problem text
3033 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3034 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3041 utf8_fullpath = mono_utf8_from_external (argv[0]);
3042 if(utf8_fullpath == NULL) {
3043 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3044 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3049 main_args [0] = utf8_fullpath;
3051 for (i = 1; i < argc; ++i) {
3054 utf8_arg=mono_utf8_from_external (argv[i]);
3055 if(utf8_arg==NULL) {
3056 /* Ditto the comment about Invalid UTF-8 here */
3057 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3058 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3062 main_args [i] = utf8_arg;
3066 if (mono_method_signature (method)->param_count) {
3067 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3068 for (i = 0; i < argc; ++i) {
3069 /* The encodings should all work, given that
3070 * we've checked all these args for the
3073 gchar *str = mono_utf8_from_external (argv [i]);
3074 MonoString *arg = mono_string_new (domain, str);
3075 mono_array_setref (args, i, arg);
3079 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3082 mono_assembly_set_main (method->klass->image->assembly);
3084 result = mono_runtime_exec_main (method, args, exc);
3085 fire_process_exit_event ();
3089 /* Used in call_unhandled_exception_delegate */
3091 create_unhandled_exception_eventargs (MonoObject *exc)
3095 MonoMethod *method = NULL;
3096 MonoBoolean is_terminating = TRUE;
3099 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
3102 mono_class_init (klass);
3104 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
3105 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
3109 args [1] = &is_terminating;
3111 obj = mono_object_new (mono_domain_get (), klass);
3112 mono_runtime_invoke (method, obj, args, NULL);
3117 /* Used in mono_unhandled_exception */
3119 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
3120 MonoObject *e = NULL;
3123 pa [0] = domain->domain;
3124 pa [1] = create_unhandled_exception_eventargs (exc);
3125 mono_runtime_delegate_invoke (delegate, pa, &e);
3128 gchar *msg = mono_string_to_utf8 (((MonoException *) e)->message);
3129 g_warning ("exception inside UnhandledException handler: %s\n", msg);
3134 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
3137 * mono_runtime_unhandled_exception_policy_set:
3138 * @policy: the new policy
3140 * This is a VM internal routine.
3142 * Sets the runtime policy for handling unhandled exceptions.
3145 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
3146 runtime_unhandled_exception_policy = policy;
3150 * mono_runtime_unhandled_exception_policy_get:
3152 * This is a VM internal routine.
3154 * Gets the runtime policy for handling unhandled exceptions.
3156 MonoRuntimeUnhandledExceptionPolicy
3157 mono_runtime_unhandled_exception_policy_get (void) {
3158 return runtime_unhandled_exception_policy;
3162 * mono_unhandled_exception:
3163 * @exc: exception thrown
3165 * This is a VM internal routine.
3167 * We call this function when we detect an unhandled exception
3168 * in the default domain.
3170 * It invokes the * UnhandledException event in AppDomain or prints
3171 * a warning to the console
3174 mono_unhandled_exception (MonoObject *exc)
3176 MonoDomain *current_domain = mono_domain_get ();
3177 MonoDomain *root_domain = mono_get_root_domain ();
3178 MonoClassField *field;
3179 MonoObject *current_appdomain_delegate;
3180 MonoObject *root_appdomain_delegate;
3182 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
3183 "UnhandledException");
3186 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
3187 gboolean abort_process = (mono_thread_current () == main_thread) ||
3188 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT);
3189 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
3190 if (current_domain != root_domain && (mono_framework_version () >= 2)) {
3191 current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
3193 current_appdomain_delegate = NULL;
3196 /* set exitcode only if we will abort the process */
3198 mono_environment_exitcode_set (1);
3199 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
3200 mono_print_unhandled_exception (exc);
3202 if (root_appdomain_delegate) {
3203 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
3205 if (current_appdomain_delegate) {
3206 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
3213 * Launch a new thread to execute a function
3215 * main_func is called back from the thread with main_args as the
3216 * parameter. The callback function is expected to start Main()
3217 * eventually. This function then waits for all managed threads to
3219 * It is not necesseray anymore to execute managed code in a subthread,
3220 * so this function should not be used anymore by default: just
3221 * execute the code and then call mono_thread_manage ().
3224 mono_runtime_exec_managed_code (MonoDomain *domain,
3225 MonoMainThreadFunc main_func,
3228 mono_thread_create (domain, main_func, main_args);
3230 mono_thread_manage ();
3234 * Execute a standard Main() method (args doesn't contain the
3238 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
3243 MonoCustomAttrInfo* cinfo;
3244 gboolean has_stathread_attribute;
3245 MonoThread* thread = mono_thread_current ();
3251 domain = mono_object_domain (args);
3252 if (!domain->entry_assembly) {
3254 MonoAssembly *assembly;
3256 assembly = method->klass->image->assembly;
3257 domain->entry_assembly = assembly;
3258 /* Domains created from another domain already have application_base and configuration_file set */
3259 if (domain->setup->application_base == NULL) {
3260 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
3263 if (domain->setup->configuration_file == NULL) {
3264 str = g_strconcat (assembly->image->name, ".config", NULL);
3265 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
3267 mono_set_private_bin_path_from_config (domain);
3271 cinfo = mono_custom_attrs_from_method (method);
3273 static MonoClass *stathread_attribute = NULL;
3274 if (!stathread_attribute)
3275 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
3276 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
3278 mono_custom_attrs_free (cinfo);
3280 has_stathread_attribute = FALSE;
3282 if (has_stathread_attribute) {
3283 thread->apartment_state = ThreadApartmentState_STA;
3284 } else if (mono_framework_version () == 1) {
3285 thread->apartment_state = ThreadApartmentState_Unknown;
3287 thread->apartment_state = ThreadApartmentState_MTA;
3289 mono_thread_init_apartment_state ();
3291 mono_debugger_event (MONO_DEBUGGER_EVENT_REACHED_MAIN, 0, 0);
3293 /* FIXME: check signature of method */
3294 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
3296 res = mono_runtime_invoke (method, NULL, pa, exc);
3298 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
3302 mono_environment_exitcode_set (rval);
3304 mono_runtime_invoke (method, NULL, pa, exc);
3308 /* If the return type of Main is void, only
3309 * set the exitcode if an exception was thrown
3310 * (we don't want to blow away an
3311 * explicitly-set exit code)
3314 mono_environment_exitcode_set (rval);
3318 mono_debugger_event (MONO_DEBUGGER_EVENT_MAIN_EXITED, (guint64) (gsize) rval, 0);
3324 * mono_install_runtime_invoke:
3325 * @func: Function to install
3327 * This is a VM internal routine
3330 mono_install_runtime_invoke (MonoInvokeFunc func)
3332 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
3337 * mono_runtime_invoke_array:
3338 * @method: method to invoke
3339 * @obJ: object instance
3340 * @params: arguments to the method
3341 * @exc: exception information.
3343 * Invokes the method represented by @method on the object @obj.
3345 * obj is the 'this' pointer, it should be NULL for static
3346 * methods, a MonoObject* for object instances and a pointer to
3347 * the value type for value types.
3349 * The params array contains the arguments to the method with the
3350 * same convention: MonoObject* pointers for object instances and
3351 * pointers to the value type otherwise. The _invoke_array
3352 * variant takes a C# object[] as the params argument (MonoArray
3353 * *params): in this case the value types are boxed inside the
3354 * respective reference representation.
3356 * From unmanaged code you'll usually use the
3357 * mono_runtime_invoke() variant.
3359 * Note that this function doesn't handle virtual methods for
3360 * you, it will exec the exact method you pass: we still need to
3361 * expose a function to lookup the derived class implementation
3362 * of a virtual method (there are examples of this in the code,
3365 * You can pass NULL as the exc argument if you don't want to
3366 * catch exceptions, otherwise, *exc will be set to the exception
3367 * thrown, if any. if an exception is thrown, you can't use the
3368 * MonoObject* result from the function.
3370 * If the method returns a value type, it is boxed in an object
3374 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
3377 MonoMethodSignature *sig = mono_method_signature (method);
3378 gpointer *pa = NULL;
3381 if (NULL != params) {
3382 pa = alloca (sizeof (gpointer) * mono_array_length (params));
3383 for (i = 0; i < mono_array_length (params); i++) {
3384 MonoType *t = sig->params [i];
3390 case MONO_TYPE_BOOLEAN:
3393 case MONO_TYPE_CHAR:
3402 case MONO_TYPE_VALUETYPE:
3403 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
3406 g_assert_not_reached ();
3407 /* The runtime invoke wrapper needs the original boxed vtype */
3408 pa [i] = mono_array_get (params, MonoObject*, i);
3410 /* MS seems to create the objects if a null is passed in */
3411 if (!mono_array_get (params, MonoObject*, i))
3412 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
3416 * We can't pass the unboxed vtype byref to the callee, since
3417 * that would mean the callee would be able to modify boxed
3418 * primitive types. So we (and MS) make a copy of the boxed
3419 * object, pass that to the callee, and replace the original
3420 * boxed object in the arg array with the copy.
3422 MonoObject *orig = mono_array_get (params, MonoObject*, i);
3423 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
3424 mono_array_setref (params, i, copy);
3427 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
3430 case MONO_TYPE_STRING:
3431 case MONO_TYPE_OBJECT:
3432 case MONO_TYPE_CLASS:
3433 case MONO_TYPE_ARRAY:
3434 case MONO_TYPE_SZARRAY:
3436 pa [i] = mono_array_addr (params, MonoObject*, i);
3437 // FIXME: I need to check this code path
3439 pa [i] = mono_array_get (params, MonoObject*, i);
3441 case MONO_TYPE_GENERICINST:
3443 t = &t->data.generic_class->container_class->this_arg;
3445 t = &t->data.generic_class->container_class->byval_arg;
3448 g_error ("type 0x%x not handled in ves_icall_InternalInvoke", sig->params [i]->type);
3453 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
3456 if (mono_class_is_nullable (method->klass)) {
3457 /* Need to create a boxed vtype instead */
3463 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
3467 obj = mono_object_new (mono_domain_get (), method->klass);
3468 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
3469 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
3471 if (method->klass->valuetype)
3472 o = mono_object_unbox (obj);
3475 } else if (method->klass->valuetype) {
3476 obj = mono_value_box (mono_domain_get (), method->klass, obj);
3479 mono_runtime_invoke (method, o, pa, exc);
3482 if (mono_class_is_nullable (method->klass)) {
3483 MonoObject *nullable;
3485 /* Convert the unboxed vtype into a Nullable structure */
3486 nullable = mono_object_new (mono_domain_get (), method->klass);
3488 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
3489 obj = mono_object_unbox (nullable);
3492 /* obj must be already unboxed if needed */
3493 return mono_runtime_invoke (method, obj, pa, exc);
3498 arith_overflow (void)
3500 mono_raise_exception (mono_get_exception_overflow ());
3504 * mono_object_allocate:
3505 * @size: number of bytes to allocate
3507 * This is a very simplistic routine until we have our GC-aware
3510 * Returns: an allocated object of size @size, or NULL on failure.
3512 static inline void *
3513 mono_object_allocate (size_t size, MonoVTable *vtable)
3516 mono_stats.new_object_count++;
3517 ALLOC_OBJECT (o, vtable, size);
3523 * mono_object_allocate_ptrfree:
3524 * @size: number of bytes to allocate
3526 * Note that the memory allocated is not zeroed.
3527 * Returns: an allocated object of size @size, or NULL on failure.
3529 static inline void *
3530 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
3533 mono_stats.new_object_count++;
3534 ALLOC_PTRFREE (o, vtable, size);
3538 static inline void *
3539 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
3542 ALLOC_TYPED (o, size, vtable);
3543 mono_stats.new_object_count++;
3550 * @klass: the class of the object that we want to create
3552 * Returns: a newly created object whose definition is
3553 * looked up using @klass. This will not invoke any constructors,
3554 * so the consumer of this routine has to invoke any constructors on
3555 * its own to initialize the object.
3558 mono_object_new (MonoDomain *domain, MonoClass *klass)
3560 MONO_ARCH_SAVE_REGS;
3561 return mono_object_new_specific (mono_class_vtable (domain, klass));
3565 * mono_object_new_specific:
3566 * @vtable: the vtable of the object that we want to create
3568 * Returns: A newly created object with class and domain specified
3572 mono_object_new_specific (MonoVTable *vtable)
3576 MONO_ARCH_SAVE_REGS;
3578 /* check for is_com_object for COM Interop */
3579 if (vtable->remote || vtable->klass->is_com_object)
3582 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
3585 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
3588 mono_class_init (klass);
3590 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
3592 vtable->domain->create_proxy_for_type_method = im;
3595 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
3597 o = mono_runtime_invoke (im, NULL, pa, NULL);
3598 if (o != NULL) return o;
3601 return mono_object_new_alloc_specific (vtable);
3605 mono_object_new_alloc_specific (MonoVTable *vtable)
3609 if (!vtable->klass->has_references) {
3610 o = mono_object_new_ptrfree (vtable);
3611 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3612 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
3614 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
3615 o = mono_object_allocate (vtable->klass->instance_size, vtable);
3617 if (G_UNLIKELY (vtable->klass->has_finalize))
3618 mono_object_register_finalizer (o);
3620 if (G_UNLIKELY (profile_allocs))
3621 mono_profiler_allocation (o, vtable->klass);
3626 mono_object_new_fast (MonoVTable *vtable)
3629 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
3634 mono_object_new_ptrfree (MonoVTable *vtable)
3637 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
3638 #if NEED_TO_ZERO_PTRFREE
3639 /* an inline memset is much faster for the common vcase of small objects
3640 * note we assume the allocated size is a multiple of sizeof (void*).
3642 if (vtable->klass->instance_size < 128) {
3644 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
3645 p = (gpointer*)((char*)obj + sizeof (MonoObject));
3651 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
3658 mono_object_new_ptrfree_box (MonoVTable *vtable)
3661 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
3662 /* the object will be boxed right away, no need to memzero it */
3667 * mono_class_get_allocation_ftn:
3669 * @for_box: the object will be used for boxing
3670 * @pass_size_in_words:
3672 * Return the allocation function appropriate for the given class.
3676 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
3678 *pass_size_in_words = FALSE;
3680 if (!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
3681 profile_allocs = FALSE;
3683 if (vtable->klass->has_finalize || vtable->klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
3684 return mono_object_new_specific;
3686 if (!vtable->klass->has_references) {
3687 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
3689 return mono_object_new_ptrfree_box;
3690 return mono_object_new_ptrfree;
3693 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3695 return mono_object_new_fast;
3698 * FIXME: This is actually slower than mono_object_new_fast, because
3699 * of the overhead of parameter passing.
3702 *pass_size_in_words = TRUE;
3703 #ifdef GC_REDIRECT_TO_LOCAL
3704 return GC_local_gcj_fast_malloc;
3706 return GC_gcj_fast_malloc;
3711 return mono_object_new_specific;
3715 * mono_object_new_from_token:
3716 * @image: Context where the type_token is hosted
3717 * @token: a token of the type that we want to create
3719 * Returns: A newly created object whose definition is
3720 * looked up using @token in the @image image
3723 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
3727 class = mono_class_get (image, token);
3729 return mono_object_new (domain, class);
3734 * mono_object_clone:
3735 * @obj: the object to clone
3737 * Returns: A newly created object who is a shallow copy of @obj
3740 mono_object_clone (MonoObject *obj)
3745 size = obj->vtable->klass->instance_size;
3746 o = mono_object_allocate (size, obj->vtable);
3747 /* do not copy the sync state */
3748 memcpy ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
3751 if (obj->vtable->klass->has_references)
3752 mono_gc_wbarrier_object (o);
3754 if (G_UNLIKELY (profile_allocs))
3755 mono_profiler_allocation (o, obj->vtable->klass);
3757 if (obj->vtable->klass->has_finalize)
3758 mono_object_register_finalizer (o);
3763 * mono_array_full_copy:
3764 * @src: source array to copy
3765 * @dest: destination array
3767 * Copies the content of one array to another with exactly the same type and size.
3770 mono_array_full_copy (MonoArray *src, MonoArray *dest)
3772 mono_array_size_t size;
3773 MonoClass *klass = src->obj.vtable->klass;
3775 MONO_ARCH_SAVE_REGS;
3777 g_assert (klass == dest->obj.vtable->klass);
3779 size = mono_array_length (src);
3780 g_assert (size == mono_array_length (dest));
3781 size *= mono_array_element_size (klass);
3783 if (klass->element_class->valuetype) {
3784 if (klass->element_class->has_references)
3785 mono_value_copy_array (dest, 0, src, mono_array_length (src));
3787 memcpy (&dest->vector, &src->vector, size);
3789 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
3792 memcpy (&dest->vector, &src->vector, size);
3797 * mono_array_clone_in_domain:
3798 * @domain: the domain in which the array will be cloned into
3799 * @array: the array to clone
3801 * This routine returns a copy of the array that is hosted on the
3802 * specified MonoDomain.
3805 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
3808 mono_array_size_t size, i;
3809 mono_array_size_t *sizes;
3810 MonoClass *klass = array->obj.vtable->klass;
3812 MONO_ARCH_SAVE_REGS;
3814 if (array->bounds == NULL) {
3815 size = mono_array_length (array);
3816 o = mono_array_new_full (domain, klass, &size, NULL);
3818 size *= mono_array_element_size (klass);
3820 if (klass->element_class->valuetype) {
3821 if (klass->element_class->has_references)
3822 mono_value_copy_array (o, 0, array, mono_array_length (array));
3824 memcpy (&o->vector, &array->vector, size);
3826 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
3829 memcpy (&o->vector, &array->vector, size);
3834 sizes = alloca (klass->rank * sizeof(mono_array_size_t) * 2);
3835 size = mono_array_element_size (klass);
3836 for (i = 0; i < klass->rank; ++i) {
3837 sizes [i] = array->bounds [i].length;
3838 size *= array->bounds [i].length;
3839 sizes [i + klass->rank] = array->bounds [i].lower_bound;
3841 o = mono_array_new_full (domain, klass, sizes, sizes + klass->rank);
3843 if (klass->element_class->valuetype) {
3844 if (klass->element_class->has_references)
3845 mono_value_copy_array (o, 0, array, mono_array_length (array));
3847 memcpy (&o->vector, &array->vector, size);
3849 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
3852 memcpy (&o->vector, &array->vector, size);
3860 * @array: the array to clone
3862 * Returns: A newly created array who is a shallow copy of @array
3865 mono_array_clone (MonoArray *array)
3867 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
3870 /* helper macros to check for overflow when calculating the size of arrays */
3871 #ifdef MONO_BIG_ARRAYS
3872 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
3873 #define MYGUINT_MAX MYGUINT64_MAX
3874 #define CHECK_ADD_OVERFLOW_UN(a,b) \
3875 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
3876 #define CHECK_MUL_OVERFLOW_UN(a,b) \
3877 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
3878 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
3880 #define MYGUINT32_MAX 4294967295U
3881 #define MYGUINT_MAX MYGUINT32_MAX
3882 #define CHECK_ADD_OVERFLOW_UN(a,b) \
3883 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
3884 #define CHECK_MUL_OVERFLOW_UN(a,b) \
3885 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
3886 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
3890 * mono_array_new_full:
3891 * @domain: domain where the object is created
3892 * @array_class: array class
3893 * @lengths: lengths for each dimension in the array
3894 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
3896 * This routine creates a new array objects with the given dimensions,
3897 * lower bounds and type.
3900 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, mono_array_size_t *lengths, mono_array_size_t *lower_bounds)
3902 mono_array_size_t byte_len, len, bounds_size;
3908 if (!array_class->inited)
3909 mono_class_init (array_class);
3911 byte_len = mono_array_element_size (array_class);
3914 /* A single dimensional array with a 0 lower bound is the same as an szarray */
3915 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
3917 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
3921 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
3923 for (i = 0; i < array_class->rank; ++i) {
3924 if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
3926 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
3927 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3932 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
3933 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3935 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
3936 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3937 byte_len += sizeof (MonoArray);
3940 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
3941 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3942 byte_len = (byte_len + 3) & ~3;
3943 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
3944 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3945 byte_len += bounds_size;
3948 * Following three lines almost taken from mono_object_new ():
3949 * they need to be kept in sync.
3951 vtable = mono_class_vtable (domain, array_class);
3952 if (!array_class->has_references) {
3953 o = mono_object_allocate_ptrfree (byte_len, vtable);
3954 #if NEED_TO_ZERO_PTRFREE
3955 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
3957 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3958 o = mono_object_allocate_spec (byte_len, vtable);
3960 o = mono_object_allocate (byte_len, vtable);
3963 array = (MonoArray*)o;
3964 array->max_length = len;
3967 MonoArrayBounds *bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
3968 array->bounds = bounds;
3969 for (i = 0; i < array_class->rank; ++i) {
3970 bounds [i].length = lengths [i];
3972 bounds [i].lower_bound = lower_bounds [i];
3976 if (G_UNLIKELY (profile_allocs))
3977 mono_profiler_allocation (o, array_class);
3984 * @domain: domain where the object is created
3985 * @eclass: element class
3986 * @n: number of array elements
3988 * This routine creates a new szarray with @n elements of type @eclass.
3991 mono_array_new (MonoDomain *domain, MonoClass *eclass, mono_array_size_t n)
3995 MONO_ARCH_SAVE_REGS;
3997 ac = mono_array_class_get (eclass, 1);
4000 return mono_array_new_specific (mono_class_vtable (domain, ac), n);
4004 * mono_array_new_specific:
4005 * @vtable: a vtable in the appropriate domain for an initialized class
4006 * @n: number of array elements
4008 * This routine is a fast alternative to mono_array_new() for code which
4009 * can be sure about the domain it operates in.
4012 mono_array_new_specific (MonoVTable *vtable, mono_array_size_t n)
4016 guint32 byte_len, elem_size;
4018 MONO_ARCH_SAVE_REGS;
4020 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
4025 elem_size = mono_array_element_size (vtable->klass);
4026 if (CHECK_MUL_OVERFLOW_UN (n, elem_size)) {
4027 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4030 byte_len = n * elem_size;
4031 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray))) {
4032 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4035 byte_len += sizeof (MonoArray);
4036 if (!vtable->klass->has_references) {
4037 o = mono_object_allocate_ptrfree (byte_len, vtable);
4038 #if NEED_TO_ZERO_PTRFREE
4039 ((MonoArray*)o)->bounds = NULL;
4040 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4042 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4043 o = mono_object_allocate_spec (byte_len, vtable);
4045 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4046 o = mono_object_allocate (byte_len, vtable);
4049 ao = (MonoArray *)o;
4051 if (G_UNLIKELY (profile_allocs))
4052 mono_profiler_allocation (o, vtable->klass);
4058 * mono_string_new_utf16:
4059 * @text: a pointer to an utf16 string
4060 * @len: the length of the string
4062 * Returns: A newly created string object which contains @text.
4065 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
4069 s = mono_string_new_size (domain, len);
4070 g_assert (s != NULL);
4072 memcpy (mono_string_chars (s), text, len * 2);
4078 * mono_string_new_size:
4079 * @text: a pointer to an utf16 string
4080 * @len: the length of the string
4082 * Returns: A newly created string object of @len
4085 mono_string_new_size (MonoDomain *domain, gint32 len)
4089 size_t size = (sizeof (MonoString) + ((len + 1) * 2));
4091 /* overflow ? can't fit it, can't allocate it! */
4093 mono_gc_out_of_memory (-1);
4095 vtable = mono_class_vtable (domain, mono_defaults.string_class);
4097 s = mono_object_allocate_ptrfree (size, vtable);
4100 #if NEED_TO_ZERO_PTRFREE
4103 if (G_UNLIKELY (profile_allocs))
4104 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
4110 * mono_string_new_len:
4111 * @text: a pointer to an utf8 string
4112 * @length: number of bytes in @text to consider
4114 * Returns: A newly created string object which contains @text.
4117 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
4119 GError *error = NULL;
4120 MonoString *o = NULL;
4122 glong items_written;
4124 ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
4127 o = mono_string_new_utf16 (domain, ut, items_written);
4129 g_error_free (error);
4138 * @text: a pointer to an utf8 string
4140 * Returns: A newly created string object which contains @text.
4143 mono_string_new (MonoDomain *domain, const char *text)
4145 GError *error = NULL;
4146 MonoString *o = NULL;
4148 glong items_written;
4153 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
4156 o = mono_string_new_utf16 (domain, ut, items_written);
4158 g_error_free (error);
4161 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
4166 MonoString *o = NULL;
4168 if (!g_utf8_validate (text, -1, &end))
4171 len = g_utf8_strlen (text, -1);
4172 o = mono_string_new_size (domain, len);
4173 str = mono_string_chars (o);
4175 while (text < end) {
4176 *str++ = g_utf8_get_char (text);
4177 text = g_utf8_next_char (text);
4184 * mono_string_new_wrapper:
4185 * @text: pointer to utf8 characters.
4187 * Helper function to create a string object from @text in the current domain.
4190 mono_string_new_wrapper (const char *text)
4192 MonoDomain *domain = mono_domain_get ();
4194 MONO_ARCH_SAVE_REGS;
4197 return mono_string_new (domain, text);
4204 * @class: the class of the value
4205 * @value: a pointer to the unboxed data
4207 * Returns: A newly created object which contains @value.
4210 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
4216 g_assert (class->valuetype);
4217 if (mono_class_is_nullable (class))
4218 return mono_nullable_box (value, class);
4220 vtable = mono_class_vtable (domain, class);
4221 size = mono_class_instance_size (class);
4222 res = mono_object_new_alloc_specific (vtable);
4223 if (G_UNLIKELY (profile_allocs))
4224 mono_profiler_allocation (res, class);
4226 size = size - sizeof (MonoObject);
4229 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
4232 #if NO_UNALIGNED_ACCESS
4233 memcpy ((char *)res + sizeof (MonoObject), value, size);
4237 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
4240 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
4243 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
4246 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
4249 memcpy ((char *)res + sizeof (MonoObject), value, size);
4252 if (class->has_finalize)
4253 mono_object_register_finalizer (res);
4259 * @dest: destination pointer
4260 * @src: source pointer
4261 * @klass: a valuetype class
4263 * Copy a valuetype from @src to @dest. This function must be used
4264 * when @klass contains references fields.
4267 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
4269 int size = mono_class_value_size (klass, NULL);
4270 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
4271 memcpy (dest, src, size);
4275 * mono_value_copy_array:
4276 * @dest: destination array
4277 * @dest_idx: index in the @dest array
4278 * @src: source pointer
4279 * @count: number of items
4281 * Copy @count valuetype items from @src to @dest. This function must be used
4282 * when @klass contains references fields.
4283 * Overlap is handled.
4286 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
4288 int size = mono_array_element_size (dest->obj.vtable->klass);
4289 char *d = mono_array_addr_with_size (dest, size, dest_idx);
4290 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
4291 memmove (d, src, size * count);
4295 * mono_object_get_domain:
4296 * @obj: object to query
4298 * Returns: the MonoDomain where the object is hosted
4301 mono_object_get_domain (MonoObject *obj)
4303 return mono_object_domain (obj);
4307 * mono_object_get_class:
4308 * @obj: object to query
4310 * Returns: the MonOClass of the object.
4313 mono_object_get_class (MonoObject *obj)
4315 return mono_object_class (obj);
4318 * mono_object_get_size:
4319 * @o: object to query
4321 * Returns: the size, in bytes, of @o
4324 mono_object_get_size (MonoObject* o)
4326 MonoClass* klass = mono_object_class (o);
4327 if (klass == mono_defaults.string_class) {
4328 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
4329 } else if (o->vtable->rank) {
4330 MonoArray *array = (MonoArray*)o;
4331 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
4332 if (array->bounds) {
4335 size += sizeof (MonoArrayBounds) * o->vtable->rank;
4339 return mono_class_instance_size (klass);
4344 * mono_object_unbox:
4345 * @obj: object to unbox
4347 * Returns: a pointer to the start of the valuetype boxed in this
4350 * This method will assert if the object passed is not a valuetype.
4353 mono_object_unbox (MonoObject *obj)
4355 /* add assert for valuetypes? */
4356 g_assert (obj->vtable->klass->valuetype);
4357 return ((char*)obj) + sizeof (MonoObject);
4361 * mono_object_isinst:
4363 * @klass: a pointer to a class
4365 * Returns: @obj if @obj is derived from @klass
4368 mono_object_isinst (MonoObject *obj, MonoClass *klass)
4371 mono_class_init (klass);
4373 if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE)
4374 return mono_object_isinst_mbyref (obj, klass);
4379 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
4383 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
4392 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4393 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
4397 MonoClass *oklass = vt->klass;
4398 if ((oklass == mono_defaults.transparent_proxy_class))
4399 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
4401 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
4405 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
4407 MonoDomain *domain = mono_domain_get ();
4409 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
4410 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
4411 MonoMethod *im = NULL;
4414 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
4415 im = mono_object_get_virtual_method (rp, im);
4418 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
4421 res = mono_runtime_invoke (im, rp, pa, NULL);
4423 if (*(MonoBoolean *) mono_object_unbox(res)) {
4424 /* Update the vtable of the remote type, so it can safely cast to this new type */
4425 mono_upgrade_remote_class (domain, obj, klass);
4434 * mono_object_castclass_mbyref:
4436 * @klass: a pointer to a class
4438 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
4441 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
4443 if (!obj) return NULL;
4444 if (mono_object_isinst_mbyref (obj, klass)) return obj;
4446 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
4448 "InvalidCastException"));
4453 MonoDomain *orig_domain;
4459 str_lookup (MonoDomain *domain, gpointer user_data)
4461 LDStrInfo *info = user_data;
4462 if (info->res || domain == info->orig_domain)
4464 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
4470 mono_string_get_pinned (MonoString *str)
4474 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
4475 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
4476 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
4477 news->length = mono_string_length (str);
4482 #define mono_string_get_pinned(str) (str)
4486 mono_string_is_interned_lookup (MonoString *str, int insert)
4488 MonoGHashTable *ldstr_table;
4492 domain = ((MonoObject *)str)->vtable->domain;
4493 ldstr_table = domain->ldstr_table;
4495 if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
4500 str = mono_string_get_pinned (str);
4501 mono_g_hash_table_insert (ldstr_table, str, str);
4505 LDStrInfo ldstr_info;
4506 ldstr_info.orig_domain = domain;
4507 ldstr_info.ins = str;
4508 ldstr_info.res = NULL;
4510 mono_domain_foreach (str_lookup, &ldstr_info);
4511 if (ldstr_info.res) {
4513 * the string was already interned in some other domain:
4514 * intern it in the current one as well.
4516 mono_g_hash_table_insert (ldstr_table, str, str);
4526 * mono_string_is_interned:
4527 * @o: String to probe
4529 * Returns whether the string has been interned.
4532 mono_string_is_interned (MonoString *o)
4534 return mono_string_is_interned_lookup (o, FALSE);
4538 * mono_string_intern:
4539 * @o: String to intern
4541 * Interns the string passed.
4542 * Returns: The interned string.
4545 mono_string_intern (MonoString *str)
4547 return mono_string_is_interned_lookup (str, TRUE);
4552 * @domain: the domain where the string will be used.
4553 * @image: a metadata context
4554 * @idx: index into the user string table.
4556 * Implementation for the ldstr opcode.
4557 * Returns: a loaded string from the @image/@idx combination.
4560 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
4562 MONO_ARCH_SAVE_REGS;
4565 return mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
4567 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
4571 * mono_ldstr_metadata_sig
4572 * @domain: the domain for the string
4573 * @sig: the signature of a metadata string
4575 * Returns: a MonoString for a string stored in the metadata
4578 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
4580 const char *str = sig;
4581 MonoString *o, *interned;
4584 len2 = mono_metadata_decode_blob_size (str, &str);
4587 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
4588 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
4591 guint16 *p2 = (guint16*)mono_string_chars (o);
4592 for (i = 0; i < len2; ++i) {
4593 *p2 = GUINT16_FROM_LE (*p2);
4599 if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
4601 /* o will get garbage collected */
4605 o = mono_string_get_pinned (o);
4606 mono_g_hash_table_insert (domain->ldstr_table, o, o);
4613 * mono_string_to_utf8:
4614 * @s: a System.String
4616 * Return the UTF8 representation for @s.
4617 * the resulting buffer nedds to be freed with g_free().
4620 mono_string_to_utf8 (MonoString *s)
4624 GError *error = NULL;
4630 return g_strdup ("");
4632 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &error);
4634 MonoException *exc = mono_get_exception_argument ("string", error->message);
4635 g_error_free (error);
4636 mono_raise_exception(exc);
4638 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
4639 if (s->length > written) {
4640 /* allocate the total length and copy the part of the string that has been converted */
4641 char *as2 = g_malloc0 (s->length);
4642 memcpy (as2, as, written);
4651 * mono_string_to_utf16:
4654 * Return an null-terminated array of the utf-16 chars
4655 * contained in @s. The result must be freed with g_free().
4656 * This is a temporary helper until our string implementation
4657 * is reworked to always include the null terminating char.
4660 mono_string_to_utf16 (MonoString *s)
4667 as = g_malloc ((s->length * 2) + 2);
4668 as [(s->length * 2)] = '\0';
4669 as [(s->length * 2) + 1] = '\0';
4672 return (gunichar2 *)(as);
4675 memcpy (as, mono_string_chars(s), s->length * 2);
4676 return (gunichar2 *)(as);
4680 * mono_string_from_utf16:
4681 * @data: the UTF16 string (LPWSTR) to convert
4683 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
4685 * Returns: a MonoString.
4688 mono_string_from_utf16 (gunichar2 *data)
4690 MonoDomain *domain = mono_domain_get ();
4696 while (data [len]) len++;
4698 return mono_string_new_utf16 (domain, data, len);
4702 * mono_string_to_utf8_mp:
4703 * @s: a System.String
4705 * Same as mono_string_to_utf8, but allocate the string from a mempool.
4708 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s)
4710 char *r = mono_string_to_utf8 (s);
4717 len = strlen (r) + 1;
4718 mp_s = mono_mempool_alloc (mp, len);
4719 memcpy (mp_s, r, len);
4727 default_ex_handler (MonoException *ex)
4729 MonoObject *o = (MonoObject*)ex;
4730 g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
4734 static MonoExceptionFunc ex_handler = default_ex_handler;
4737 * mono_install_handler:
4738 * @func: exception handler
4740 * This is an internal JIT routine used to install the handler for exceptions
4744 mono_install_handler (MonoExceptionFunc func)
4746 ex_handler = func? func: default_ex_handler;
4750 * mono_raise_exception:
4751 * @ex: exception object
4753 * Signal the runtime that the exception @ex has been raised in unmanaged code.
4756 mono_raise_exception (MonoException *ex)
4759 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
4760 * that will cause gcc to omit the function epilog, causing problems when
4761 * the JIT tries to walk the stack, since the return address on the stack
4762 * will point into the next function in the executable, not this one.
4765 if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class)
4766 MONO_OBJECT_SETREF (mono_thread_current (), abort_exc, ex);
4772 * mono_wait_handle_new:
4773 * @domain: Domain where the object will be created
4774 * @handle: Handle for the wait handle
4776 * Returns: A new MonoWaitHandle created in the given domain for the given handle
4779 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
4781 MonoWaitHandle *res;
4782 gpointer params [1];
4783 static MonoMethod *handle_set;
4785 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.waithandle_class);
4787 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
4789 handle_set = mono_class_get_property_from_name (mono_defaults.waithandle_class, "Handle")->set;
4791 params [0] = &handle;
4792 mono_runtime_invoke (handle_set, res, params, NULL);
4798 mono_wait_handle_get_handle (MonoWaitHandle *handle)
4800 static MonoClassField *f_os_handle;
4801 static MonoClassField *f_safe_handle;
4803 if (!f_os_handle && !f_safe_handle) {
4804 f_os_handle = mono_class_get_field_from_name (mono_defaults.waithandle_class, "os_handle");
4805 f_safe_handle = mono_class_get_field_from_name (mono_defaults.waithandle_class, "safe_wait_handle");
4810 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
4814 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
4820 * mono_async_result_new:
4821 * @domain:domain where the object will be created.
4822 * @handle: wait handle.
4823 * @state: state to pass to AsyncResult
4824 * @data: C closure data.
4826 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
4827 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
4831 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
4833 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
4834 MonoMethod *method = mono_get_context_capture_method ();
4836 /* we must capture the execution context from the original thread */
4838 MONO_OBJECT_SETREF (res, execution_context, mono_runtime_invoke (method, NULL, NULL, NULL));
4839 /* note: result may be null if the flow is suppressed */
4843 MONO_OBJECT_SETREF (res, object_data, object_data);
4844 MONO_OBJECT_SETREF (res, async_state, state);
4846 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
4848 res->sync_completed = FALSE;
4849 res->completed = FALSE;
4855 mono_message_init (MonoDomain *domain,
4856 MonoMethodMessage *this,
4857 MonoReflectionMethod *method,
4858 MonoArray *out_args)
4860 static MonoClass *object_array_klass;
4861 static MonoClass *byte_array_klass;
4862 static MonoClass *string_array_klass;
4863 MonoMethodSignature *sig = mono_method_signature (method->method);
4869 if (!object_array_klass) {
4872 klass = mono_array_class_get (mono_defaults.object_class, 1);
4875 mono_memory_barrier ();
4876 object_array_klass = klass;
4878 klass = mono_array_class_get (mono_defaults.byte_class, 1);
4881 mono_memory_barrier ();
4882 byte_array_klass = klass;
4884 klass = mono_array_class_get (mono_defaults.string_class, 1);
4887 mono_memory_barrier ();
4888 string_array_klass = klass;
4891 MONO_OBJECT_SETREF (this, method, method);
4893 MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
4894 MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
4895 this->async_result = NULL;
4896 this->call_type = CallType_Sync;
4898 names = g_new (char *, sig->param_count);
4899 mono_method_get_param_names (method->method, (const char **) names);
4900 MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
4902 for (i = 0; i < sig->param_count; i++) {
4903 name = mono_string_new (domain, names [i]);
4904 mono_array_setref (this->names, i, name);
4908 for (i = 0, j = 0; i < sig->param_count; i++) {
4909 if (sig->params [i]->byref) {
4911 MonoObject* arg = mono_array_get (out_args, gpointer, j);
4912 mono_array_setref (this->args, i, arg);
4916 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
4920 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
4923 mono_array_set (this->arg_types, guint8, i, arg_type);
4928 * mono_remoting_invoke:
4929 * @real_proxy: pointer to a RealProxy object
4930 * @msg: The MonoMethodMessage to execute
4931 * @exc: used to store exceptions
4932 * @out_args: used to store output arguments
4934 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
4935 * IMessage interface and it is not trivial to extract results from there. So
4936 * we call an helper method PrivateInvoke instead of calling
4937 * RealProxy::Invoke() directly.
4939 * Returns: the result object.
4942 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
4943 MonoObject **exc, MonoArray **out_args)
4945 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
4948 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
4951 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
4953 real_proxy->vtable->domain->private_invoke_method = im;
4956 pa [0] = real_proxy;
4961 return mono_runtime_invoke (im, NULL, pa, exc);
4965 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
4966 MonoObject **exc, MonoArray **out_args)
4968 static MonoClass *object_array_klass;
4971 MonoMethodSignature *sig;
4973 int i, j, outarg_count = 0;
4975 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
4977 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
4978 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
4979 target = tp->rp->unwrapped_server;
4981 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
4985 domain = mono_domain_get ();
4986 method = msg->method->method;
4987 sig = mono_method_signature (method);
4989 for (i = 0; i < sig->param_count; i++) {
4990 if (sig->params [i]->byref)
4994 if (!object_array_klass) {
4997 klass = mono_array_class_get (mono_defaults.object_class, 1);
5000 mono_memory_barrier ();
5001 object_array_klass = klass;
5004 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
5005 *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
5008 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
5010 for (i = 0, j = 0; i < sig->param_count; i++) {
5011 if (sig->params [i]->byref) {
5013 arg = mono_array_get (msg->args, gpointer, i);
5014 mono_array_setref (*out_args, j, arg);
5023 * mono_print_unhandled_exception:
5024 * @exc: The exception
5026 * Prints the unhandled exception.
5029 mono_print_unhandled_exception (MonoObject *exc)
5031 char *message = (char *) "";
5035 gboolean free_message = FALSE;
5037 if (mono_object_isinst (exc, mono_defaults.exception_class)) {
5038 klass = exc->vtable->klass;
5040 while (klass && method == NULL) {
5041 method = mono_class_get_method_from_name_flags (klass, "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
5043 klass = klass->parent;
5048 str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL);
5050 message = mono_string_to_utf8 (str);
5051 free_message = TRUE;
5056 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
5057 * exc->vtable->klass->name, message);
5059 g_printerr ("\nUnhandled Exception: %s\n", message);
5066 * mono_delegate_ctor:
5067 * @this: pointer to an uninitialized delegate object
5068 * @target: target object
5069 * @addr: pointer to native code
5072 * Initialize a delegate and sets a specific method, not the one
5073 * associated with addr. This is useful when sharing generic code.
5074 * In that case addr will most probably not be associated with the
5075 * correct instantiation of the method.
5078 mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer addr, MonoMethod *method)
5080 MonoDelegate *delegate = (MonoDelegate *)this;
5087 delegate->method = method;
5089 class = this->vtable->klass;
5090 mono_stats.delegate_creations++;
5092 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5094 method = mono_marshal_get_remoting_invoke (method);
5095 delegate->method_ptr = mono_compile_method (method);
5096 MONO_OBJECT_SETREF (delegate, target, target);
5097 } else if (mono_method_signature (method)->hasthis && method->klass->valuetype) {
5098 method = mono_marshal_get_unbox_wrapper (method);
5099 delegate->method_ptr = mono_compile_method (method);
5100 MONO_OBJECT_SETREF (delegate, target, target);
5102 delegate->method_ptr = addr;
5103 MONO_OBJECT_SETREF (delegate, target, target);
5106 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->klass);
5110 * mono_delegate_ctor:
5111 * @this: pointer to an uninitialized delegate object
5112 * @target: target object
5113 * @addr: pointer to native code
5115 * This is used to initialize a delegate.
5118 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
5120 MonoDomain *domain = mono_domain_get ();
5122 MonoMethod *method = NULL;
5126 if ((ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr)))) {
5127 method = ji->method;
5128 g_assert (!method->klass->generic_container);
5131 mono_delegate_ctor_with_method (this, target, addr, method);
5135 * mono_method_call_message_new:
5136 * @method: method to encapsulate
5137 * @params: parameters to the method
5138 * @invoke: optional, delegate invoke.
5139 * @cb: async callback delegate.
5140 * @state: state passed to the async callback.
5142 * Translates arguments pointers into a MonoMethodMessage.
5145 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
5146 MonoDelegate **cb, MonoObject **state)
5148 MonoDomain *domain = mono_domain_get ();
5149 MonoMethodSignature *sig = mono_method_signature (method);
5150 MonoMethodMessage *msg;
5153 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5156 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
5157 count = sig->param_count - 2;
5159 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
5160 count = sig->param_count;
5163 for (i = 0; i < count; i++) {
5168 if (sig->params [i]->byref)
5169 vpos = *((gpointer *)params [i]);
5173 type = sig->params [i]->type;
5174 class = mono_class_from_mono_type (sig->params [i]);
5176 if (class->valuetype)
5177 arg = mono_value_box (domain, class, vpos);
5179 arg = *((MonoObject **)vpos);
5181 mono_array_setref (msg->args, i, arg);
5184 if (cb != NULL && state != NULL) {
5185 *cb = *((MonoDelegate **)params [i]);
5187 *state = *((MonoObject **)params [i]);
5194 * mono_method_return_message_restore:
5196 * Restore results from message based processing back to arguments pointers
5199 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
5201 MonoMethodSignature *sig = mono_method_signature (method);
5202 int i, j, type, size, out_len;
5204 if (out_args == NULL)
5206 out_len = mono_array_length (out_args);
5210 for (i = 0, j = 0; i < sig->param_count; i++) {
5211 MonoType *pt = sig->params [i];
5216 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
5218 arg = mono_array_get (out_args, gpointer, j);
5222 case MONO_TYPE_VOID:
5223 g_assert_not_reached ();
5227 case MONO_TYPE_BOOLEAN:
5230 case MONO_TYPE_CHAR:
5237 case MONO_TYPE_VALUETYPE: {
5239 size = mono_class_value_size (((MonoObject*)arg)->vtable->klass, NULL);
5240 memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
5243 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
5244 memset (*((gpointer *)params [i]), 0, size);
5248 case MONO_TYPE_STRING:
5249 case MONO_TYPE_CLASS:
5250 case MONO_TYPE_ARRAY:
5251 case MONO_TYPE_SZARRAY:
5252 case MONO_TYPE_OBJECT:
5253 **((MonoObject ***)params [i]) = (MonoObject *)arg;
5256 g_assert_not_reached ();
5265 * mono_load_remote_field:
5266 * @this: pointer to an object
5267 * @klass: klass of the object containing @field
5268 * @field: the field to load
5269 * @res: a storage to store the result
5271 * This method is called by the runtime on attempts to load fields of
5272 * transparent proxy objects. @this points to such TP, @klass is the class of
5273 * the object containing @field. @res is a storage location which can be
5274 * used to store the result.
5276 * Returns: an address pointing to the value of field.
5279 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
5281 static MonoMethod *getter = NULL;
5282 MonoDomain *domain = mono_domain_get ();
5283 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5284 MonoClass *field_class;
5285 MonoMethodMessage *msg;
5286 MonoArray *out_args;
5290 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5291 g_assert (res != NULL);
5293 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5294 mono_field_get_value (tp->rp->unwrapped_server, field, res);
5299 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
5303 field_class = mono_class_from_mono_type (field->type);
5305 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5306 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
5307 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
5309 full_name = mono_type_get_full_name (klass);
5310 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5311 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5314 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5316 if (exc) mono_raise_exception ((MonoException *)exc);
5318 if (mono_array_length (out_args) == 0)
5321 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
5323 if (field_class->valuetype) {
5324 return ((char *)*res) + sizeof (MonoObject);
5330 * mono_load_remote_field_new:
5335 * Missing documentation.
5338 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
5340 static MonoMethod *getter = NULL;
5341 MonoDomain *domain = mono_domain_get ();
5342 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5343 MonoClass *field_class;
5344 MonoMethodMessage *msg;
5345 MonoArray *out_args;
5346 MonoObject *exc, *res;
5349 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5351 field_class = mono_class_from_mono_type (field->type);
5353 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5355 if (field_class->valuetype) {
5356 res = mono_object_new (domain, field_class);
5357 val = ((gchar *) res) + sizeof (MonoObject);
5361 mono_field_get_value (tp->rp->unwrapped_server, field, val);
5366 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
5370 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5371 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
5373 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
5375 full_name = mono_type_get_full_name (klass);
5376 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5377 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5380 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5382 if (exc) mono_raise_exception ((MonoException *)exc);
5384 if (mono_array_length (out_args) == 0)
5387 res = mono_array_get (out_args, MonoObject *, 0);
5393 * mono_store_remote_field:
5394 * @this: pointer to an object
5395 * @klass: klass of the object containing @field
5396 * @field: the field to load
5397 * @val: the value/object to store
5399 * This method is called by the runtime on attempts to store fields of
5400 * transparent proxy objects. @this points to such TP, @klass is the class of
5401 * the object containing @field. @val is the new value to store in @field.
5404 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
5406 static MonoMethod *setter = NULL;
5407 MonoDomain *domain = mono_domain_get ();
5408 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5409 MonoClass *field_class;
5410 MonoMethodMessage *msg;
5411 MonoArray *out_args;
5416 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5418 field_class = mono_class_from_mono_type (field->type);
5420 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5421 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
5422 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
5427 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
5431 if (field_class->valuetype)
5432 arg = mono_value_box (domain, field_class, val);
5434 arg = *((MonoObject **)val);
5437 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5438 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
5440 full_name = mono_type_get_full_name (klass);
5441 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5442 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5443 mono_array_setref (msg->args, 2, arg);
5446 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5448 if (exc) mono_raise_exception ((MonoException *)exc);
5452 * mono_store_remote_field_new:
5458 * Missing documentation
5461 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
5463 static MonoMethod *setter = NULL;
5464 MonoDomain *domain = mono_domain_get ();
5465 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5466 MonoClass *field_class;
5467 MonoMethodMessage *msg;
5468 MonoArray *out_args;
5472 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5474 field_class = mono_class_from_mono_type (field->type);
5476 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5477 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
5478 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
5483 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
5487 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5488 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
5490 full_name = mono_type_get_full_name (klass);
5491 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5492 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5493 mono_array_setref (msg->args, 2, arg);
5496 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5498 if (exc) mono_raise_exception ((MonoException *)exc);
5502 * mono_create_ftnptr:
5504 * Given a function address, create a function descriptor for it.
5505 * This is only needed on IA64 and PPC64.
5508 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
5513 mono_domain_lock (domain);
5514 desc = mono_code_manager_reserve (domain->code_mp, 2 * sizeof (gpointer));
5515 mono_domain_unlock (domain);
5521 #elif defined(__ppc64__) || defined(__powerpc64__)
5524 mono_domain_lock (domain);
5525 desc = mono_code_manager_reserve (domain->code_mp, 3 * sizeof (gpointer));
5526 mono_domain_unlock (domain);
5539 * mono_get_addr_from_ftnptr:
5541 * Given a pointer to a function descriptor, return the function address.
5542 * This is only needed on IA64 and PPC64.
5545 mono_get_addr_from_ftnptr (gpointer descr)
5547 #if defined(__ia64__) || defined(__ppc64__) || defined(__powerpc64__)
5548 return *(gpointer*)descr;
5556 * mono_string_chars:
5559 * Returns a pointer to the UCS16 characters stored in the MonoString
5562 mono_string_chars(MonoString *s)
5564 /* This method is here only for documentation extraction, this is a macro */
5568 * mono_string_length:
5571 * Returns the lenght in characters of the string
5574 mono_string_length (MonoString *s)
5576 /* This method is here only for documentation extraction, this is a macro */