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 = 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 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
3260 str = g_strconcat (assembly->image->name, ".config", NULL);
3261 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
3263 mono_set_private_bin_path_from_config (domain);
3266 cinfo = mono_custom_attrs_from_method (method);
3268 static MonoClass *stathread_attribute = NULL;
3269 if (!stathread_attribute)
3270 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
3271 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
3273 mono_custom_attrs_free (cinfo);
3275 has_stathread_attribute = FALSE;
3277 if (has_stathread_attribute) {
3278 thread->apartment_state = ThreadApartmentState_STA;
3279 } else if (mono_framework_version () == 1) {
3280 thread->apartment_state = ThreadApartmentState_Unknown;
3282 thread->apartment_state = ThreadApartmentState_MTA;
3284 mono_thread_init_apartment_state ();
3286 mono_debugger_event (MONO_DEBUGGER_EVENT_REACHED_MAIN, 0, 0);
3288 /* FIXME: check signature of method */
3289 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
3291 res = mono_runtime_invoke (method, NULL, pa, exc);
3293 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
3297 mono_environment_exitcode_set (rval);
3299 mono_runtime_invoke (method, NULL, pa, exc);
3303 /* If the return type of Main is void, only
3304 * set the exitcode if an exception was thrown
3305 * (we don't want to blow away an
3306 * explicitly-set exit code)
3309 mono_environment_exitcode_set (rval);
3313 mono_debugger_event (MONO_DEBUGGER_EVENT_MAIN_EXITED, (guint64) (gsize) rval, 0);
3319 * mono_install_runtime_invoke:
3320 * @func: Function to install
3322 * This is a VM internal routine
3325 mono_install_runtime_invoke (MonoInvokeFunc func)
3327 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
3332 * mono_runtime_invoke_array:
3333 * @method: method to invoke
3334 * @obJ: object instance
3335 * @params: arguments to the method
3336 * @exc: exception information.
3338 * Invokes the method represented by @method on the object @obj.
3340 * obj is the 'this' pointer, it should be NULL for static
3341 * methods, a MonoObject* for object instances and a pointer to
3342 * the value type for value types.
3344 * The params array contains the arguments to the method with the
3345 * same convention: MonoObject* pointers for object instances and
3346 * pointers to the value type otherwise. The _invoke_array
3347 * variant takes a C# object[] as the params argument (MonoArray
3348 * *params): in this case the value types are boxed inside the
3349 * respective reference representation.
3351 * From unmanaged code you'll usually use the
3352 * mono_runtime_invoke() variant.
3354 * Note that this function doesn't handle virtual methods for
3355 * you, it will exec the exact method you pass: we still need to
3356 * expose a function to lookup the derived class implementation
3357 * of a virtual method (there are examples of this in the code,
3360 * You can pass NULL as the exc argument if you don't want to
3361 * catch exceptions, otherwise, *exc will be set to the exception
3362 * thrown, if any. if an exception is thrown, you can't use the
3363 * MonoObject* result from the function.
3365 * If the method returns a value type, it is boxed in an object
3369 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
3372 MonoMethodSignature *sig = mono_method_signature (method);
3373 gpointer *pa = NULL;
3376 if (NULL != params) {
3377 pa = alloca (sizeof (gpointer) * mono_array_length (params));
3378 for (i = 0; i < mono_array_length (params); i++) {
3379 MonoType *t = sig->params [i];
3385 case MONO_TYPE_BOOLEAN:
3388 case MONO_TYPE_CHAR:
3397 case MONO_TYPE_VALUETYPE:
3398 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
3401 g_assert_not_reached ();
3402 /* The runtime invoke wrapper needs the original boxed vtype */
3403 pa [i] = mono_array_get (params, MonoObject*, i);
3405 /* MS seems to create the objects if a null is passed in */
3406 if (!mono_array_get (params, MonoObject*, i))
3407 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
3411 * We can't pass the unboxed vtype byref to the callee, since
3412 * that would mean the callee would be able to modify boxed
3413 * primitive types. So we (and MS) make a copy of the boxed
3414 * object, pass that to the callee, and replace the original
3415 * boxed object in the arg array with the copy.
3417 MonoObject *orig = mono_array_get (params, MonoObject*, i);
3418 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
3419 mono_array_setref (params, i, copy);
3422 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
3425 case MONO_TYPE_STRING:
3426 case MONO_TYPE_OBJECT:
3427 case MONO_TYPE_CLASS:
3428 case MONO_TYPE_ARRAY:
3429 case MONO_TYPE_SZARRAY:
3431 pa [i] = mono_array_addr (params, MonoObject*, i);
3432 // FIXME: I need to check this code path
3434 pa [i] = mono_array_get (params, MonoObject*, i);
3436 case MONO_TYPE_GENERICINST:
3438 t = &t->data.generic_class->container_class->this_arg;
3440 t = &t->data.generic_class->container_class->byval_arg;
3443 g_error ("type 0x%x not handled in ves_icall_InternalInvoke", sig->params [i]->type);
3448 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
3451 if (mono_class_is_nullable (method->klass)) {
3452 /* Need to create a boxed vtype instead */
3458 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
3462 obj = mono_object_new (mono_domain_get (), method->klass);
3463 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
3464 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
3466 if (method->klass->valuetype)
3467 o = mono_object_unbox (obj);
3470 } else if (method->klass->valuetype) {
3471 obj = mono_value_box (mono_domain_get (), method->klass, obj);
3474 mono_runtime_invoke (method, o, pa, exc);
3477 if (mono_class_is_nullable (method->klass)) {
3478 MonoObject *nullable;
3480 /* Convert the unboxed vtype into a Nullable structure */
3481 nullable = mono_object_new (mono_domain_get (), method->klass);
3483 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
3484 obj = mono_object_unbox (nullable);
3487 /* obj must be already unboxed if needed */
3488 return mono_runtime_invoke (method, obj, pa, exc);
3493 arith_overflow (void)
3495 mono_raise_exception (mono_get_exception_overflow ());
3499 * mono_object_allocate:
3500 * @size: number of bytes to allocate
3502 * This is a very simplistic routine until we have our GC-aware
3505 * Returns: an allocated object of size @size, or NULL on failure.
3507 static inline void *
3508 mono_object_allocate (size_t size, MonoVTable *vtable)
3511 mono_stats.new_object_count++;
3512 ALLOC_OBJECT (o, vtable, size);
3518 * mono_object_allocate_ptrfree:
3519 * @size: number of bytes to allocate
3521 * Note that the memory allocated is not zeroed.
3522 * Returns: an allocated object of size @size, or NULL on failure.
3524 static inline void *
3525 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
3528 mono_stats.new_object_count++;
3529 ALLOC_PTRFREE (o, vtable, size);
3533 static inline void *
3534 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
3537 ALLOC_TYPED (o, size, vtable);
3538 mono_stats.new_object_count++;
3545 * @klass: the class of the object that we want to create
3547 * Returns: a newly created object whose definition is
3548 * looked up using @klass. This will not invoke any constructors,
3549 * so the consumer of this routine has to invoke any constructors on
3550 * its own to initialize the object.
3553 mono_object_new (MonoDomain *domain, MonoClass *klass)
3555 MONO_ARCH_SAVE_REGS;
3556 return mono_object_new_specific (mono_class_vtable (domain, klass));
3560 * mono_object_new_specific:
3561 * @vtable: the vtable of the object that we want to create
3563 * Returns: A newly created object with class and domain specified
3567 mono_object_new_specific (MonoVTable *vtable)
3571 MONO_ARCH_SAVE_REGS;
3573 /* check for is_com_object for COM Interop */
3574 if (vtable->remote || vtable->klass->is_com_object)
3577 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
3580 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
3583 mono_class_init (klass);
3585 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
3587 vtable->domain->create_proxy_for_type_method = im;
3590 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
3592 o = mono_runtime_invoke (im, NULL, pa, NULL);
3593 if (o != NULL) return o;
3596 return mono_object_new_alloc_specific (vtable);
3600 mono_object_new_alloc_specific (MonoVTable *vtable)
3604 if (!vtable->klass->has_references) {
3605 o = mono_object_new_ptrfree (vtable);
3606 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3607 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
3609 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
3610 o = mono_object_allocate (vtable->klass->instance_size, vtable);
3612 if (G_UNLIKELY (vtable->klass->has_finalize))
3613 mono_object_register_finalizer (o);
3615 if (G_UNLIKELY (profile_allocs))
3616 mono_profiler_allocation (o, vtable->klass);
3621 mono_object_new_fast (MonoVTable *vtable)
3624 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
3629 mono_object_new_ptrfree (MonoVTable *vtable)
3632 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
3633 #if NEED_TO_ZERO_PTRFREE
3634 /* an inline memset is much faster for the common vcase of small objects
3635 * note we assume the allocated size is a multiple of sizeof (void*).
3637 if (vtable->klass->instance_size < 128) {
3639 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
3640 p = (gpointer*)((char*)obj + sizeof (MonoObject));
3646 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
3653 mono_object_new_ptrfree_box (MonoVTable *vtable)
3656 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
3657 /* the object will be boxed right away, no need to memzero it */
3662 * mono_class_get_allocation_ftn:
3664 * @for_box: the object will be used for boxing
3665 * @pass_size_in_words:
3667 * Return the allocation function appropriate for the given class.
3671 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
3673 *pass_size_in_words = FALSE;
3675 if (!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
3676 profile_allocs = FALSE;
3678 if (vtable->klass->has_finalize || vtable->klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
3679 return mono_object_new_specific;
3681 if (!vtable->klass->has_references) {
3682 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
3684 return mono_object_new_ptrfree_box;
3685 return mono_object_new_ptrfree;
3688 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3690 return mono_object_new_fast;
3693 * FIXME: This is actually slower than mono_object_new_fast, because
3694 * of the overhead of parameter passing.
3697 *pass_size_in_words = TRUE;
3698 #ifdef GC_REDIRECT_TO_LOCAL
3699 return GC_local_gcj_fast_malloc;
3701 return GC_gcj_fast_malloc;
3706 return mono_object_new_specific;
3710 * mono_object_new_from_token:
3711 * @image: Context where the type_token is hosted
3712 * @token: a token of the type that we want to create
3714 * Returns: A newly created object whose definition is
3715 * looked up using @token in the @image image
3718 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
3722 class = mono_class_get (image, token);
3724 return mono_object_new (domain, class);
3729 * mono_object_clone:
3730 * @obj: the object to clone
3732 * Returns: A newly created object who is a shallow copy of @obj
3735 mono_object_clone (MonoObject *obj)
3740 size = obj->vtable->klass->instance_size;
3741 o = mono_object_allocate (size, obj->vtable);
3742 /* do not copy the sync state */
3743 memcpy ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
3746 if (obj->vtable->klass->has_references)
3747 mono_gc_wbarrier_object (o);
3749 if (G_UNLIKELY (profile_allocs))
3750 mono_profiler_allocation (o, obj->vtable->klass);
3752 if (obj->vtable->klass->has_finalize)
3753 mono_object_register_finalizer (o);
3758 * mono_array_full_copy:
3759 * @src: source array to copy
3760 * @dest: destination array
3762 * Copies the content of one array to another with exactly the same type and size.
3765 mono_array_full_copy (MonoArray *src, MonoArray *dest)
3767 mono_array_size_t size;
3768 MonoClass *klass = src->obj.vtable->klass;
3770 MONO_ARCH_SAVE_REGS;
3772 g_assert (klass == dest->obj.vtable->klass);
3774 size = mono_array_length (src);
3775 g_assert (size == mono_array_length (dest));
3776 size *= mono_array_element_size (klass);
3778 if (klass->element_class->valuetype) {
3779 if (klass->element_class->has_references)
3780 mono_value_copy_array (dest, 0, src, mono_array_length (src));
3782 memcpy (&dest->vector, &src->vector, size);
3784 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
3787 memcpy (&dest->vector, &src->vector, size);
3792 * mono_array_clone_in_domain:
3793 * @domain: the domain in which the array will be cloned into
3794 * @array: the array to clone
3796 * This routine returns a copy of the array that is hosted on the
3797 * specified MonoDomain.
3800 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
3803 mono_array_size_t size, i;
3804 mono_array_size_t *sizes;
3805 MonoClass *klass = array->obj.vtable->klass;
3807 MONO_ARCH_SAVE_REGS;
3809 if (array->bounds == NULL) {
3810 size = mono_array_length (array);
3811 o = mono_array_new_full (domain, klass, &size, NULL);
3813 size *= mono_array_element_size (klass);
3815 if (klass->element_class->valuetype) {
3816 if (klass->element_class->has_references)
3817 mono_value_copy_array (o, 0, array, mono_array_length (array));
3819 memcpy (&o->vector, &array->vector, size);
3821 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
3824 memcpy (&o->vector, &array->vector, size);
3829 sizes = alloca (klass->rank * sizeof(mono_array_size_t) * 2);
3830 size = mono_array_element_size (klass);
3831 for (i = 0; i < klass->rank; ++i) {
3832 sizes [i] = array->bounds [i].length;
3833 size *= array->bounds [i].length;
3834 sizes [i + klass->rank] = array->bounds [i].lower_bound;
3836 o = mono_array_new_full (domain, klass, sizes, sizes + klass->rank);
3838 if (klass->element_class->valuetype) {
3839 if (klass->element_class->has_references)
3840 mono_value_copy_array (o, 0, array, mono_array_length (array));
3842 memcpy (&o->vector, &array->vector, size);
3844 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
3847 memcpy (&o->vector, &array->vector, size);
3855 * @array: the array to clone
3857 * Returns: A newly created array who is a shallow copy of @array
3860 mono_array_clone (MonoArray *array)
3862 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
3865 /* helper macros to check for overflow when calculating the size of arrays */
3866 #ifdef MONO_BIG_ARRAYS
3867 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
3868 #define MYGUINT_MAX MYGUINT64_MAX
3869 #define CHECK_ADD_OVERFLOW_UN(a,b) \
3870 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
3871 #define CHECK_MUL_OVERFLOW_UN(a,b) \
3872 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
3873 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
3875 #define MYGUINT32_MAX 4294967295U
3876 #define MYGUINT_MAX MYGUINT32_MAX
3877 #define CHECK_ADD_OVERFLOW_UN(a,b) \
3878 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
3879 #define CHECK_MUL_OVERFLOW_UN(a,b) \
3880 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
3881 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
3885 * mono_array_new_full:
3886 * @domain: domain where the object is created
3887 * @array_class: array class
3888 * @lengths: lengths for each dimension in the array
3889 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
3891 * This routine creates a new array objects with the given dimensions,
3892 * lower bounds and type.
3895 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, mono_array_size_t *lengths, mono_array_size_t *lower_bounds)
3897 mono_array_size_t byte_len, len, bounds_size;
3903 if (!array_class->inited)
3904 mono_class_init (array_class);
3906 byte_len = mono_array_element_size (array_class);
3909 /* A single dimensional array with a 0 lower bound is the same as an szarray */
3910 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
3912 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
3916 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
3918 for (i = 0; i < array_class->rank; ++i) {
3919 if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
3921 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
3922 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3927 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
3928 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3930 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
3931 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3932 byte_len += sizeof (MonoArray);
3935 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
3936 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3937 byte_len = (byte_len + 3) & ~3;
3938 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
3939 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3940 byte_len += bounds_size;
3943 * Following three lines almost taken from mono_object_new ():
3944 * they need to be kept in sync.
3946 vtable = mono_class_vtable (domain, array_class);
3947 if (!array_class->has_references) {
3948 o = mono_object_allocate_ptrfree (byte_len, vtable);
3949 #if NEED_TO_ZERO_PTRFREE
3950 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
3952 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3953 o = mono_object_allocate_spec (byte_len, vtable);
3955 o = mono_object_allocate (byte_len, vtable);
3958 array = (MonoArray*)o;
3959 array->max_length = len;
3962 MonoArrayBounds *bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
3963 array->bounds = bounds;
3964 for (i = 0; i < array_class->rank; ++i) {
3965 bounds [i].length = lengths [i];
3967 bounds [i].lower_bound = lower_bounds [i];
3971 if (G_UNLIKELY (profile_allocs))
3972 mono_profiler_allocation (o, array_class);
3979 * @domain: domain where the object is created
3980 * @eclass: element class
3981 * @n: number of array elements
3983 * This routine creates a new szarray with @n elements of type @eclass.
3986 mono_array_new (MonoDomain *domain, MonoClass *eclass, mono_array_size_t n)
3990 MONO_ARCH_SAVE_REGS;
3992 ac = mono_array_class_get (eclass, 1);
3995 return mono_array_new_specific (mono_class_vtable (domain, ac), n);
3999 * mono_array_new_specific:
4000 * @vtable: a vtable in the appropriate domain for an initialized class
4001 * @n: number of array elements
4003 * This routine is a fast alternative to mono_array_new() for code which
4004 * can be sure about the domain it operates in.
4007 mono_array_new_specific (MonoVTable *vtable, mono_array_size_t n)
4011 guint32 byte_len, elem_size;
4013 MONO_ARCH_SAVE_REGS;
4015 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
4020 elem_size = mono_array_element_size (vtable->klass);
4021 if (CHECK_MUL_OVERFLOW_UN (n, elem_size)) {
4022 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4025 byte_len = n * elem_size;
4026 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray))) {
4027 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4030 byte_len += sizeof (MonoArray);
4031 if (!vtable->klass->has_references) {
4032 o = mono_object_allocate_ptrfree (byte_len, vtable);
4033 #if NEED_TO_ZERO_PTRFREE
4034 ((MonoArray*)o)->bounds = NULL;
4035 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4037 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4038 o = mono_object_allocate_spec (byte_len, vtable);
4040 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4041 o = mono_object_allocate (byte_len, vtable);
4044 ao = (MonoArray *)o;
4046 if (G_UNLIKELY (profile_allocs))
4047 mono_profiler_allocation (o, vtable->klass);
4053 * mono_string_new_utf16:
4054 * @text: a pointer to an utf16 string
4055 * @len: the length of the string
4057 * Returns: A newly created string object which contains @text.
4060 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
4064 s = mono_string_new_size (domain, len);
4065 g_assert (s != NULL);
4067 memcpy (mono_string_chars (s), text, len * 2);
4073 * mono_string_new_size:
4074 * @text: a pointer to an utf16 string
4075 * @len: the length of the string
4077 * Returns: A newly created string object of @len
4080 mono_string_new_size (MonoDomain *domain, gint32 len)
4084 size_t size = (sizeof (MonoString) + ((len + 1) * 2));
4086 /* overflow ? can't fit it, can't allocate it! */
4088 mono_gc_out_of_memory (-1);
4090 vtable = mono_class_vtable (domain, mono_defaults.string_class);
4092 s = mono_object_allocate_ptrfree (size, vtable);
4095 #if NEED_TO_ZERO_PTRFREE
4098 if (G_UNLIKELY (profile_allocs))
4099 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
4105 * mono_string_new_len:
4106 * @text: a pointer to an utf8 string
4107 * @length: number of bytes in @text to consider
4109 * Returns: A newly created string object which contains @text.
4112 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
4114 GError *error = NULL;
4115 MonoString *o = NULL;
4117 glong items_written;
4119 ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
4122 o = mono_string_new_utf16 (domain, ut, items_written);
4124 g_error_free (error);
4133 * @text: a pointer to an utf8 string
4135 * Returns: A newly created string object which contains @text.
4138 mono_string_new (MonoDomain *domain, const char *text)
4140 GError *error = NULL;
4141 MonoString *o = NULL;
4143 glong items_written;
4148 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
4151 o = mono_string_new_utf16 (domain, ut, items_written);
4153 g_error_free (error);
4156 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
4161 MonoString *o = NULL;
4163 if (!g_utf8_validate (text, -1, &end))
4166 len = g_utf8_strlen (text, -1);
4167 o = mono_string_new_size (domain, len);
4168 str = mono_string_chars (o);
4170 while (text < end) {
4171 *str++ = g_utf8_get_char (text);
4172 text = g_utf8_next_char (text);
4179 * mono_string_new_wrapper:
4180 * @text: pointer to utf8 characters.
4182 * Helper function to create a string object from @text in the current domain.
4185 mono_string_new_wrapper (const char *text)
4187 MonoDomain *domain = mono_domain_get ();
4189 MONO_ARCH_SAVE_REGS;
4192 return mono_string_new (domain, text);
4199 * @class: the class of the value
4200 * @value: a pointer to the unboxed data
4202 * Returns: A newly created object which contains @value.
4205 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
4211 g_assert (class->valuetype);
4212 if (mono_class_is_nullable (class))
4213 return mono_nullable_box (value, class);
4215 vtable = mono_class_vtable (domain, class);
4216 size = mono_class_instance_size (class);
4217 res = mono_object_new_alloc_specific (vtable);
4218 if (G_UNLIKELY (profile_allocs))
4219 mono_profiler_allocation (res, class);
4221 size = size - sizeof (MonoObject);
4224 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
4227 #if NO_UNALIGNED_ACCESS
4228 memcpy ((char *)res + sizeof (MonoObject), value, size);
4232 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
4235 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
4238 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
4241 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
4244 memcpy ((char *)res + sizeof (MonoObject), value, size);
4247 if (class->has_finalize)
4248 mono_object_register_finalizer (res);
4254 * @dest: destination pointer
4255 * @src: source pointer
4256 * @klass: a valuetype class
4258 * Copy a valuetype from @src to @dest. This function must be used
4259 * when @klass contains references fields.
4262 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
4264 int size = mono_class_value_size (klass, NULL);
4265 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
4266 memcpy (dest, src, size);
4270 * mono_value_copy_array:
4271 * @dest: destination array
4272 * @dest_idx: index in the @dest array
4273 * @src: source pointer
4274 * @count: number of items
4276 * Copy @count valuetype items from @src to @dest. This function must be used
4277 * when @klass contains references fields.
4278 * Overlap is handled.
4281 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
4283 int size = mono_array_element_size (dest->obj.vtable->klass);
4284 char *d = mono_array_addr_with_size (dest, size, dest_idx);
4285 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
4286 memmove (d, src, size * count);
4290 * mono_object_get_domain:
4291 * @obj: object to query
4293 * Returns: the MonoDomain where the object is hosted
4296 mono_object_get_domain (MonoObject *obj)
4298 return mono_object_domain (obj);
4302 * mono_object_get_class:
4303 * @obj: object to query
4305 * Returns: the MonOClass of the object.
4308 mono_object_get_class (MonoObject *obj)
4310 return mono_object_class (obj);
4313 * mono_object_get_size:
4314 * @o: object to query
4316 * Returns: the size, in bytes, of @o
4319 mono_object_get_size (MonoObject* o)
4321 MonoClass* klass = mono_object_class (o);
4322 if (klass == mono_defaults.string_class) {
4323 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
4324 } else if (o->vtable->rank) {
4325 MonoArray *array = (MonoArray*)o;
4326 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
4327 if (array->bounds) {
4330 size += sizeof (MonoArrayBounds) * o->vtable->rank;
4334 return mono_class_instance_size (klass);
4339 * mono_object_unbox:
4340 * @obj: object to unbox
4342 * Returns: a pointer to the start of the valuetype boxed in this
4345 * This method will assert if the object passed is not a valuetype.
4348 mono_object_unbox (MonoObject *obj)
4350 /* add assert for valuetypes? */
4351 g_assert (obj->vtable->klass->valuetype);
4352 return ((char*)obj) + sizeof (MonoObject);
4356 * mono_object_isinst:
4358 * @klass: a pointer to a class
4360 * Returns: @obj if @obj is derived from @klass
4363 mono_object_isinst (MonoObject *obj, MonoClass *klass)
4366 mono_class_init (klass);
4368 if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE)
4369 return mono_object_isinst_mbyref (obj, klass);
4374 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
4378 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
4387 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4388 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
4392 MonoClass *oklass = vt->klass;
4393 if ((oklass == mono_defaults.transparent_proxy_class))
4394 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
4396 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
4400 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
4402 MonoDomain *domain = mono_domain_get ();
4404 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
4405 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
4406 MonoMethod *im = NULL;
4409 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
4410 im = mono_object_get_virtual_method (rp, im);
4413 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
4416 res = mono_runtime_invoke (im, rp, pa, NULL);
4418 if (*(MonoBoolean *) mono_object_unbox(res)) {
4419 /* Update the vtable of the remote type, so it can safely cast to this new type */
4420 mono_upgrade_remote_class (domain, obj, klass);
4429 * mono_object_castclass_mbyref:
4431 * @klass: a pointer to a class
4433 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
4436 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
4438 if (!obj) return NULL;
4439 if (mono_object_isinst_mbyref (obj, klass)) return obj;
4441 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
4443 "InvalidCastException"));
4448 MonoDomain *orig_domain;
4454 str_lookup (MonoDomain *domain, gpointer user_data)
4456 LDStrInfo *info = user_data;
4457 if (info->res || domain == info->orig_domain)
4459 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
4465 mono_string_get_pinned (MonoString *str)
4469 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
4470 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
4471 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
4472 news->length = mono_string_length (str);
4477 #define mono_string_get_pinned(str) (str)
4481 mono_string_is_interned_lookup (MonoString *str, int insert)
4483 MonoGHashTable *ldstr_table;
4487 domain = ((MonoObject *)str)->vtable->domain;
4488 ldstr_table = domain->ldstr_table;
4490 if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
4495 str = mono_string_get_pinned (str);
4496 mono_g_hash_table_insert (ldstr_table, str, str);
4500 LDStrInfo ldstr_info;
4501 ldstr_info.orig_domain = domain;
4502 ldstr_info.ins = str;
4503 ldstr_info.res = NULL;
4505 mono_domain_foreach (str_lookup, &ldstr_info);
4506 if (ldstr_info.res) {
4508 * the string was already interned in some other domain:
4509 * intern it in the current one as well.
4511 mono_g_hash_table_insert (ldstr_table, str, str);
4521 * mono_string_is_interned:
4522 * @o: String to probe
4524 * Returns whether the string has been interned.
4527 mono_string_is_interned (MonoString *o)
4529 return mono_string_is_interned_lookup (o, FALSE);
4533 * mono_string_intern:
4534 * @o: String to intern
4536 * Interns the string passed.
4537 * Returns: The interned string.
4540 mono_string_intern (MonoString *str)
4542 return mono_string_is_interned_lookup (str, TRUE);
4547 * @domain: the domain where the string will be used.
4548 * @image: a metadata context
4549 * @idx: index into the user string table.
4551 * Implementation for the ldstr opcode.
4552 * Returns: a loaded string from the @image/@idx combination.
4555 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
4557 MONO_ARCH_SAVE_REGS;
4560 return mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
4562 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
4566 * mono_ldstr_metadata_sig
4567 * @domain: the domain for the string
4568 * @sig: the signature of a metadata string
4570 * Returns: a MonoString for a string stored in the metadata
4573 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
4575 const char *str = sig;
4576 MonoString *o, *interned;
4579 len2 = mono_metadata_decode_blob_size (str, &str);
4582 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
4583 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
4586 guint16 *p2 = (guint16*)mono_string_chars (o);
4587 for (i = 0; i < len2; ++i) {
4588 *p2 = GUINT16_FROM_LE (*p2);
4594 if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
4596 /* o will get garbage collected */
4600 o = mono_string_get_pinned (o);
4601 mono_g_hash_table_insert (domain->ldstr_table, o, o);
4608 * mono_string_to_utf8:
4609 * @s: a System.String
4611 * Return the UTF8 representation for @s.
4612 * the resulting buffer nedds to be freed with g_free().
4615 mono_string_to_utf8 (MonoString *s)
4619 GError *error = NULL;
4625 return g_strdup ("");
4627 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &error);
4629 MonoException *exc = mono_get_exception_argument ("string", error->message);
4630 g_error_free (error);
4631 mono_raise_exception(exc);
4633 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
4634 if (s->length > written) {
4635 /* allocate the total length and copy the part of the string that has been converted */
4636 char *as2 = g_malloc0 (s->length);
4637 memcpy (as2, as, written);
4646 * mono_string_to_utf16:
4649 * Return an null-terminated array of the utf-16 chars
4650 * contained in @s. The result must be freed with g_free().
4651 * This is a temporary helper until our string implementation
4652 * is reworked to always include the null terminating char.
4655 mono_string_to_utf16 (MonoString *s)
4662 as = g_malloc ((s->length * 2) + 2);
4663 as [(s->length * 2)] = '\0';
4664 as [(s->length * 2) + 1] = '\0';
4667 return (gunichar2 *)(as);
4670 memcpy (as, mono_string_chars(s), s->length * 2);
4671 return (gunichar2 *)(as);
4675 * mono_string_from_utf16:
4676 * @data: the UTF16 string (LPWSTR) to convert
4678 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
4680 * Returns: a MonoString.
4683 mono_string_from_utf16 (gunichar2 *data)
4685 MonoDomain *domain = mono_domain_get ();
4691 while (data [len]) len++;
4693 return mono_string_new_utf16 (domain, data, len);
4697 * mono_string_to_utf8_mp:
4698 * @s: a System.String
4700 * Same as mono_string_to_utf8, but allocate the string from a mempool.
4703 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s)
4705 char *r = mono_string_to_utf8 (s);
4712 len = strlen (r) + 1;
4713 mp_s = mono_mempool_alloc (mp, len);
4714 memcpy (mp_s, r, len);
4722 default_ex_handler (MonoException *ex)
4724 MonoObject *o = (MonoObject*)ex;
4725 g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
4729 static MonoExceptionFunc ex_handler = default_ex_handler;
4732 * mono_install_handler:
4733 * @func: exception handler
4735 * This is an internal JIT routine used to install the handler for exceptions
4739 mono_install_handler (MonoExceptionFunc func)
4741 ex_handler = func? func: default_ex_handler;
4745 * mono_raise_exception:
4746 * @ex: exception object
4748 * Signal the runtime that the exception @ex has been raised in unmanaged code.
4751 mono_raise_exception (MonoException *ex)
4754 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
4755 * that will cause gcc to omit the function epilog, causing problems when
4756 * the JIT tries to walk the stack, since the return address on the stack
4757 * will point into the next function in the executable, not this one.
4760 if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class)
4761 MONO_OBJECT_SETREF (mono_thread_current (), abort_exc, ex);
4767 * mono_wait_handle_new:
4768 * @domain: Domain where the object will be created
4769 * @handle: Handle for the wait handle
4771 * Returns: A new MonoWaitHandle created in the given domain for the given handle
4774 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
4776 MonoWaitHandle *res;
4777 gpointer params [1];
4778 static MonoMethod *handle_set;
4780 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.waithandle_class);
4782 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
4784 handle_set = mono_class_get_property_from_name (mono_defaults.waithandle_class, "Handle")->set;
4786 params [0] = &handle;
4787 mono_runtime_invoke (handle_set, res, params, NULL);
4793 mono_wait_handle_get_handle (MonoWaitHandle *handle)
4795 static MonoClassField *f_os_handle;
4796 static MonoClassField *f_safe_handle;
4798 if (!f_os_handle && !f_safe_handle) {
4799 f_os_handle = mono_class_get_field_from_name (mono_defaults.waithandle_class, "os_handle");
4800 f_safe_handle = mono_class_get_field_from_name (mono_defaults.waithandle_class, "safe_wait_handle");
4805 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
4809 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
4815 * mono_async_result_new:
4816 * @domain:domain where the object will be created.
4817 * @handle: wait handle.
4818 * @state: state to pass to AsyncResult
4819 * @data: C closure data.
4821 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
4822 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
4826 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
4828 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
4829 MonoMethod *method = mono_get_context_capture_method ();
4831 /* we must capture the execution context from the original thread */
4833 MONO_OBJECT_SETREF (res, execution_context, mono_runtime_invoke (method, NULL, NULL, NULL));
4834 /* note: result may be null if the flow is suppressed */
4838 MONO_OBJECT_SETREF (res, object_data, object_data);
4839 MONO_OBJECT_SETREF (res, async_state, state);
4841 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
4843 res->sync_completed = FALSE;
4844 res->completed = FALSE;
4850 mono_message_init (MonoDomain *domain,
4851 MonoMethodMessage *this,
4852 MonoReflectionMethod *method,
4853 MonoArray *out_args)
4855 static MonoClass *object_array_klass;
4856 static MonoClass *byte_array_klass;
4857 static MonoClass *string_array_klass;
4858 MonoMethodSignature *sig = mono_method_signature (method->method);
4864 if (!object_array_klass) {
4867 klass = mono_array_class_get (mono_defaults.object_class, 1);
4870 mono_memory_barrier ();
4871 object_array_klass = klass;
4873 klass = mono_array_class_get (mono_defaults.byte_class, 1);
4876 mono_memory_barrier ();
4877 byte_array_klass = klass;
4879 klass = mono_array_class_get (mono_defaults.string_class, 1);
4882 mono_memory_barrier ();
4883 string_array_klass = klass;
4886 MONO_OBJECT_SETREF (this, method, method);
4888 MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
4889 MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
4890 this->async_result = NULL;
4891 this->call_type = CallType_Sync;
4893 names = g_new (char *, sig->param_count);
4894 mono_method_get_param_names (method->method, (const char **) names);
4895 MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
4897 for (i = 0; i < sig->param_count; i++) {
4898 name = mono_string_new (domain, names [i]);
4899 mono_array_setref (this->names, i, name);
4903 for (i = 0, j = 0; i < sig->param_count; i++) {
4904 if (sig->params [i]->byref) {
4906 MonoObject* arg = mono_array_get (out_args, gpointer, j);
4907 mono_array_setref (this->args, i, arg);
4911 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
4915 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
4918 mono_array_set (this->arg_types, guint8, i, arg_type);
4923 * mono_remoting_invoke:
4924 * @real_proxy: pointer to a RealProxy object
4925 * @msg: The MonoMethodMessage to execute
4926 * @exc: used to store exceptions
4927 * @out_args: used to store output arguments
4929 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
4930 * IMessage interface and it is not trivial to extract results from there. So
4931 * we call an helper method PrivateInvoke instead of calling
4932 * RealProxy::Invoke() directly.
4934 * Returns: the result object.
4937 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
4938 MonoObject **exc, MonoArray **out_args)
4940 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
4943 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
4946 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
4948 real_proxy->vtable->domain->private_invoke_method = im;
4951 pa [0] = real_proxy;
4956 return mono_runtime_invoke (im, NULL, pa, exc);
4960 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
4961 MonoObject **exc, MonoArray **out_args)
4963 static MonoClass *object_array_klass;
4966 MonoMethodSignature *sig;
4968 int i, j, outarg_count = 0;
4970 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
4972 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
4973 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
4974 target = tp->rp->unwrapped_server;
4976 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
4980 domain = mono_domain_get ();
4981 method = msg->method->method;
4982 sig = mono_method_signature (method);
4984 for (i = 0; i < sig->param_count; i++) {
4985 if (sig->params [i]->byref)
4989 if (!object_array_klass) {
4992 klass = mono_array_class_get (mono_defaults.object_class, 1);
4995 mono_memory_barrier ();
4996 object_array_klass = klass;
4999 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
5000 *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
5003 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
5005 for (i = 0, j = 0; i < sig->param_count; i++) {
5006 if (sig->params [i]->byref) {
5008 arg = mono_array_get (msg->args, gpointer, i);
5009 mono_array_setref (*out_args, j, arg);
5018 * mono_print_unhandled_exception:
5019 * @exc: The exception
5021 * Prints the unhandled exception.
5024 mono_print_unhandled_exception (MonoObject *exc)
5026 char *message = (char *) "";
5030 gboolean free_message = FALSE;
5032 if (mono_object_isinst (exc, mono_defaults.exception_class)) {
5033 klass = exc->vtable->klass;
5035 while (klass && method == NULL) {
5036 method = mono_class_get_method_from_name_flags (klass, "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
5038 klass = klass->parent;
5043 str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL);
5045 message = mono_string_to_utf8 (str);
5046 free_message = TRUE;
5051 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
5052 * exc->vtable->klass->name, message);
5054 g_printerr ("\nUnhandled Exception: %s\n", message);
5061 * mono_delegate_ctor:
5062 * @this: pointer to an uninitialized delegate object
5063 * @target: target object
5064 * @addr: pointer to native code
5067 * Initialize a delegate and sets a specific method, not the one
5068 * associated with addr. This is useful when sharing generic code.
5069 * In that case addr will most probably not be associated with the
5070 * correct instantiation of the method.
5073 mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer addr, MonoMethod *method)
5075 MonoDelegate *delegate = (MonoDelegate *)this;
5082 delegate->method = method;
5084 class = this->vtable->klass;
5085 mono_stats.delegate_creations++;
5087 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5089 method = mono_marshal_get_remoting_invoke (method);
5090 delegate->method_ptr = mono_compile_method (method);
5091 MONO_OBJECT_SETREF (delegate, target, target);
5092 } else if (mono_method_signature (method)->hasthis && method->klass->valuetype) {
5093 method = mono_marshal_get_unbox_wrapper (method);
5094 delegate->method_ptr = mono_compile_method (method);
5095 MONO_OBJECT_SETREF (delegate, target, target);
5097 delegate->method_ptr = addr;
5098 MONO_OBJECT_SETREF (delegate, target, target);
5101 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->klass);
5105 * mono_delegate_ctor:
5106 * @this: pointer to an uninitialized delegate object
5107 * @target: target object
5108 * @addr: pointer to native code
5110 * This is used to initialize a delegate.
5113 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
5115 MonoDomain *domain = mono_domain_get ();
5117 MonoMethod *method = NULL;
5121 if ((ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr)))) {
5122 method = ji->method;
5123 g_assert (!method->klass->generic_container);
5126 mono_delegate_ctor_with_method (this, target, addr, method);
5130 * mono_method_call_message_new:
5131 * @method: method to encapsulate
5132 * @params: parameters to the method
5133 * @invoke: optional, delegate invoke.
5134 * @cb: async callback delegate.
5135 * @state: state passed to the async callback.
5137 * Translates arguments pointers into a MonoMethodMessage.
5140 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
5141 MonoDelegate **cb, MonoObject **state)
5143 MonoDomain *domain = mono_domain_get ();
5144 MonoMethodSignature *sig = mono_method_signature (method);
5145 MonoMethodMessage *msg;
5148 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5151 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
5152 count = sig->param_count - 2;
5154 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
5155 count = sig->param_count;
5158 for (i = 0; i < count; i++) {
5163 if (sig->params [i]->byref)
5164 vpos = *((gpointer *)params [i]);
5168 type = sig->params [i]->type;
5169 class = mono_class_from_mono_type (sig->params [i]);
5171 if (class->valuetype)
5172 arg = mono_value_box (domain, class, vpos);
5174 arg = *((MonoObject **)vpos);
5176 mono_array_setref (msg->args, i, arg);
5179 if (cb != NULL && state != NULL) {
5180 *cb = *((MonoDelegate **)params [i]);
5182 *state = *((MonoObject **)params [i]);
5189 * mono_method_return_message_restore:
5191 * Restore results from message based processing back to arguments pointers
5194 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
5196 MonoMethodSignature *sig = mono_method_signature (method);
5197 int i, j, type, size, out_len;
5199 if (out_args == NULL)
5201 out_len = mono_array_length (out_args);
5205 for (i = 0, j = 0; i < sig->param_count; i++) {
5206 MonoType *pt = sig->params [i];
5211 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
5213 arg = mono_array_get (out_args, gpointer, j);
5217 case MONO_TYPE_VOID:
5218 g_assert_not_reached ();
5222 case MONO_TYPE_BOOLEAN:
5225 case MONO_TYPE_CHAR:
5232 case MONO_TYPE_VALUETYPE: {
5234 size = mono_class_value_size (((MonoObject*)arg)->vtable->klass, NULL);
5235 memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
5238 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
5239 memset (*((gpointer *)params [i]), 0, size);
5243 case MONO_TYPE_STRING:
5244 case MONO_TYPE_CLASS:
5245 case MONO_TYPE_ARRAY:
5246 case MONO_TYPE_SZARRAY:
5247 case MONO_TYPE_OBJECT:
5248 **((MonoObject ***)params [i]) = (MonoObject *)arg;
5251 g_assert_not_reached ();
5260 * mono_load_remote_field:
5261 * @this: pointer to an object
5262 * @klass: klass of the object containing @field
5263 * @field: the field to load
5264 * @res: a storage to store the result
5266 * This method is called by the runtime on attempts to load fields of
5267 * transparent proxy objects. @this points to such TP, @klass is the class of
5268 * the object containing @field. @res is a storage location which can be
5269 * used to store the result.
5271 * Returns: an address pointing to the value of field.
5274 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
5276 static MonoMethod *getter = NULL;
5277 MonoDomain *domain = mono_domain_get ();
5278 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5279 MonoClass *field_class;
5280 MonoMethodMessage *msg;
5281 MonoArray *out_args;
5285 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5286 g_assert (res != NULL);
5288 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5289 mono_field_get_value (tp->rp->unwrapped_server, field, res);
5294 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
5298 field_class = mono_class_from_mono_type (field->type);
5300 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5301 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
5302 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
5304 full_name = mono_type_get_full_name (klass);
5305 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5306 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5309 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5311 if (exc) mono_raise_exception ((MonoException *)exc);
5313 if (mono_array_length (out_args) == 0)
5316 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
5318 if (field_class->valuetype) {
5319 return ((char *)*res) + sizeof (MonoObject);
5325 * mono_load_remote_field_new:
5330 * Missing documentation.
5333 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
5335 static MonoMethod *getter = NULL;
5336 MonoDomain *domain = mono_domain_get ();
5337 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5338 MonoClass *field_class;
5339 MonoMethodMessage *msg;
5340 MonoArray *out_args;
5341 MonoObject *exc, *res;
5344 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5346 field_class = mono_class_from_mono_type (field->type);
5348 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5350 if (field_class->valuetype) {
5351 res = mono_object_new (domain, field_class);
5352 val = ((gchar *) res) + sizeof (MonoObject);
5356 mono_field_get_value (tp->rp->unwrapped_server, field, val);
5361 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
5365 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5366 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
5368 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
5370 full_name = mono_type_get_full_name (klass);
5371 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5372 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5375 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5377 if (exc) mono_raise_exception ((MonoException *)exc);
5379 if (mono_array_length (out_args) == 0)
5382 res = mono_array_get (out_args, MonoObject *, 0);
5388 * mono_store_remote_field:
5389 * @this: pointer to an object
5390 * @klass: klass of the object containing @field
5391 * @field: the field to load
5392 * @val: the value/object to store
5394 * This method is called by the runtime on attempts to store fields of
5395 * transparent proxy objects. @this points to such TP, @klass is the class of
5396 * the object containing @field. @val is the new value to store in @field.
5399 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
5401 static MonoMethod *setter = NULL;
5402 MonoDomain *domain = mono_domain_get ();
5403 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5404 MonoClass *field_class;
5405 MonoMethodMessage *msg;
5406 MonoArray *out_args;
5411 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5413 field_class = mono_class_from_mono_type (field->type);
5415 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5416 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
5417 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
5422 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
5426 if (field_class->valuetype)
5427 arg = mono_value_box (domain, field_class, val);
5429 arg = *((MonoObject **)val);
5432 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5433 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
5435 full_name = mono_type_get_full_name (klass);
5436 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5437 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5438 mono_array_setref (msg->args, 2, arg);
5441 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5443 if (exc) mono_raise_exception ((MonoException *)exc);
5447 * mono_store_remote_field_new:
5453 * Missing documentation
5456 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
5458 static MonoMethod *setter = NULL;
5459 MonoDomain *domain = mono_domain_get ();
5460 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5461 MonoClass *field_class;
5462 MonoMethodMessage *msg;
5463 MonoArray *out_args;
5467 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5469 field_class = mono_class_from_mono_type (field->type);
5471 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5472 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
5473 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
5478 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
5482 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5483 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
5485 full_name = mono_type_get_full_name (klass);
5486 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5487 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5488 mono_array_setref (msg->args, 2, arg);
5491 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5493 if (exc) mono_raise_exception ((MonoException *)exc);
5497 * mono_create_ftnptr:
5499 * Given a function address, create a function descriptor for it.
5500 * This is only needed on IA64 and PPC64.
5503 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
5508 mono_domain_lock (domain);
5509 desc = mono_code_manager_reserve (domain->code_mp, 2 * sizeof (gpointer));
5510 mono_domain_unlock (domain);
5516 #elif defined(__ppc64__) || defined(__powerpc64__)
5519 mono_domain_lock (domain);
5520 desc = mono_code_manager_reserve (domain->code_mp, 3 * sizeof (gpointer));
5521 mono_domain_unlock (domain);
5534 * mono_get_addr_from_ftnptr:
5536 * Given a pointer to a function descriptor, return the function address.
5537 * This is only needed on IA64 and PPC64.
5540 mono_get_addr_from_ftnptr (gpointer descr)
5542 #if defined(__ia64__) || defined(__ppc64__) || defined(__powerpc64__)
5543 return *(gpointer*)descr;
5551 * mono_string_chars:
5554 * Returns a pointer to the UCS16 characters stored in the MonoString
5557 mono_string_chars(MonoString *s)
5559 /* This method is here only for documentation extraction, this is a macro */
5563 * mono_string_length:
5566 * Returns the lenght in characters of the string
5569 mono_string_length (MonoString *s)
5571 /* This method is here only for documentation extraction, this is a macro */