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 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
1715 t = (char*)vt->data + field->offset;
1716 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
1719 if (fklass->valuetype) {
1720 memcpy (t, field->data, mono_class_value_size (fklass, NULL));
1722 /* it's a pointer type: add check */
1723 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
1724 *t = *(char *)field->data;
1730 vt->max_interface_id = class->max_interface_id;
1731 vt->interface_bitmap = class->interface_bitmap;
1733 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
1734 // class->name, class->interface_offsets_count);
1736 if (! ARCH_USE_IMT) {
1737 /* initialize interface offsets */
1738 for (i = 0; i < class->interface_offsets_count; ++i) {
1739 int interface_id = class->interfaces_packed [i]->interface_id;
1740 int slot = class->interface_offsets_packed [i];
1741 interface_offsets [class->max_interface_id - interface_id] = &(vt->vtable [slot]);
1745 /* FIXME: class_vtable_hash is basically obsolete now: remove as soon
1746 * as we change the code in appdomain.c to invalidate vtables by
1747 * looking at the possible MonoClasses created for the domain.
1749 g_hash_table_insert (domain->class_vtable_hash, class, vt);
1750 /* class->runtime_info is protected by the loader lock, both when
1751 * it it enlarged and when it is stored info.
1753 mono_loader_lock ();
1754 old_info = class->runtime_info;
1755 if (old_info && old_info->max_domain >= domain->domain_id) {
1756 /* someone already created a large enough runtime info */
1757 mono_memory_barrier ();
1758 old_info->domain_vtables [domain->domain_id] = vt;
1760 int new_size = domain->domain_id;
1762 new_size = MAX (new_size, old_info->max_domain);
1764 /* make the new size a power of two */
1766 while (new_size > i)
1769 /* this is a bounded memory retention issue: may want to
1770 * handle it differently when we'll have a rcu-like system.
1772 runtime_info = mono_image_alloc0 (class->image, sizeof (MonoClassRuntimeInfo) + new_size * sizeof (gpointer));
1773 runtime_info->max_domain = new_size - 1;
1774 /* copy the stuff from the older info */
1776 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
1778 runtime_info->domain_vtables [domain->domain_id] = vt;
1780 mono_memory_barrier ();
1781 class->runtime_info = runtime_info;
1783 mono_loader_unlock ();
1785 /* Initialize vtable */
1786 if (vtable_trampoline) {
1787 // This also covers the AOT case
1788 for (i = 0; i < class->vtable_size; ++i) {
1789 vt->vtable [i] = vtable_trampoline;
1792 mono_class_setup_vtable (class);
1794 for (i = 0; i < class->vtable_size; ++i) {
1797 if ((cm = class->vtable [i])) {
1798 if (mono_method_signature (cm)->generic_param_count)
1799 /* FIXME: Why is this needed ? */
1800 vt->vtable [i] = cm;
1802 vt->vtable [i] = vtable_trampoline? vtable_trampoline: arch_create_jit_trampoline (cm);
1807 if (ARCH_USE_IMT && imt_table_bytes) {
1808 /* Now that the vtable is full, we can actually fill up the IMT */
1809 if (imt_trampoline) {
1810 /* lazy construction of the IMT entries enabled */
1811 for (i = 0; i < MONO_IMT_SIZE; ++i)
1812 interface_offsets [i] = imt_trampoline;
1814 build_imt (class, vt, domain, interface_offsets, NULL);
1818 mono_domain_unlock (domain);
1820 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
1821 if (mono_is_security_manager_active () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND)) {
1822 MonoException *exc = mono_class_get_exception_for_failure (class);
1824 mono_raise_exception (exc);
1827 /* make sure the parent is initialized */
1829 mono_class_vtable (domain, class->parent);
1831 vt->type = mono_type_get_object (domain, &class->byval_arg);
1832 if (class->contextbound)
1841 * mono_class_proxy_vtable:
1842 * @domain: the application domain
1843 * @remove_class: the remote class
1845 * Creates a vtable for transparent proxies. It is basically
1846 * a copy of the real vtable of the class wrapped in @remote_class,
1847 * but all function pointers invoke the remoting functions, and
1848 * vtable->klass points to the transparent proxy class, and not to @class.
1851 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
1853 MonoVTable *vt, *pvt;
1854 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
1856 GSList *extra_interfaces = NULL;
1857 MonoClass *class = remote_class->proxy_class;
1858 gpointer *interface_offsets;
1860 vt = mono_class_vtable (domain, class);
1861 max_interface_id = vt->max_interface_id;
1863 /* Calculate vtable space for extra interfaces */
1864 for (j = 0; j < remote_class->interface_count; j++) {
1865 MonoClass* iclass = remote_class->interfaces[j];
1869 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
1870 continue; /* interface implemented by the class */
1871 if (g_slist_find (extra_interfaces, iclass))
1874 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
1876 method_count = mono_class_num_methods (iclass);
1878 ifaces = mono_class_get_implemented_interfaces (iclass);
1880 for (i = 0; i < ifaces->len; ++i) {
1881 MonoClass *ic = g_ptr_array_index (ifaces, i);
1882 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
1883 continue; /* interface implemented by the class */
1884 if (g_slist_find (extra_interfaces, ic))
1886 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
1887 method_count += mono_class_num_methods (ic);
1889 g_ptr_array_free (ifaces, TRUE);
1892 extra_interface_vtsize += method_count * sizeof (gpointer);
1893 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
1897 mono_stats.imt_number_of_tables++;
1898 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
1899 vtsize = sizeof (gpointer) * (MONO_IMT_SIZE) +
1900 sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
1902 vtsize = sizeof (gpointer) * (max_interface_id + 1) +
1903 sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
1906 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
1908 interface_offsets = mono_domain_alloc0 (domain, vtsize + extra_interface_vtsize);
1910 pvt = (MonoVTable*) (interface_offsets + MONO_IMT_SIZE);
1912 pvt = (MonoVTable*) (interface_offsets + max_interface_id + 1);
1913 memcpy (pvt, vt, sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer));
1915 pvt->klass = mono_defaults.transparent_proxy_class;
1916 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
1917 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
1919 /* initialize vtable */
1920 mono_class_setup_vtable (class);
1921 for (i = 0; i < class->vtable_size; ++i) {
1924 if ((cm = class->vtable [i]))
1925 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
1927 pvt->vtable [i] = NULL;
1930 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
1931 /* create trampolines for abstract methods */
1932 for (k = class; k; k = k->parent) {
1934 gpointer iter = NULL;
1935 while ((m = mono_class_get_methods (k, &iter)))
1936 if (!pvt->vtable [m->slot])
1937 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
1941 pvt->max_interface_id = max_interface_id;
1942 pvt->interface_bitmap = mono_domain_alloc0 (domain, sizeof (guint8) * (max_interface_id/8 + 1 ));
1944 if (! ARCH_USE_IMT) {
1945 /* initialize interface offsets */
1946 for (i = 0; i < class->interface_offsets_count; ++i) {
1947 int interface_id = class->interfaces_packed [i]->interface_id;
1948 int slot = class->interface_offsets_packed [i];
1949 interface_offsets [class->max_interface_id - interface_id] = &(pvt->vtable [slot]);
1952 for (i = 0; i < class->interface_offsets_count; ++i) {
1953 int interface_id = class->interfaces_packed [i]->interface_id;
1954 pvt->interface_bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
1957 if (extra_interfaces) {
1958 int slot = class->vtable_size;
1964 /* Create trampolines for the methods of the interfaces */
1965 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1966 interf = list_item->data;
1968 if (! ARCH_USE_IMT) {
1969 interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
1971 pvt->interface_bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
1975 while ((cm = mono_class_get_methods (interf, &iter)))
1976 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
1978 slot += mono_class_num_methods (interf);
1980 if (! ARCH_USE_IMT) {
1981 g_slist_free (extra_interfaces);
1986 /* Now that the vtable is full, we can actually fill up the IMT */
1987 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
1988 if (extra_interfaces) {
1989 g_slist_free (extra_interfaces);
1997 * mono_class_field_is_special_static:
1999 * Returns whether @field is a thread/context static field.
2002 mono_class_field_is_special_static (MonoClassField *field)
2004 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2006 if (mono_field_is_deleted (field))
2008 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2009 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2016 * mono_class_has_special_static_fields:
2018 * Returns whenever @klass has any thread/context static fields.
2021 mono_class_has_special_static_fields (MonoClass *klass)
2023 MonoClassField *field;
2027 while ((field = mono_class_get_fields (klass, &iter))) {
2028 g_assert (field->parent == klass);
2029 if (mono_class_field_is_special_static (field))
2037 * create_remote_class_key:
2038 * Creates an array of pointers that can be used as a hash key for a remote class.
2039 * The first element of the array is the number of pointers.
2042 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2047 if (remote_class == NULL) {
2048 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2049 key = g_malloc (sizeof(gpointer) * 3);
2050 key [0] = GINT_TO_POINTER (2);
2051 key [1] = mono_defaults.marshalbyrefobject_class;
2052 key [2] = extra_class;
2054 key = g_malloc (sizeof(gpointer) * 2);
2055 key [0] = GINT_TO_POINTER (1);
2056 key [1] = extra_class;
2059 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2060 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2061 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2062 key [1] = remote_class->proxy_class;
2064 // Keep the list of interfaces sorted
2065 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2066 if (extra_class && remote_class->interfaces [i] > extra_class) {
2067 key [j++] = extra_class;
2070 key [j] = remote_class->interfaces [i];
2073 key [j] = extra_class;
2075 // Replace the old class. The interface list is the same
2076 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2077 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2078 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2079 for (i = 0; i < remote_class->interface_count; i++)
2080 key [2 + i] = remote_class->interfaces [i];
2088 * copy_remote_class_key:
2090 * Make a copy of KEY in the domain and return the copy.
2093 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2095 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2096 gpointer *mp_key = mono_domain_alloc (domain, key_size);
2098 memcpy (mp_key, key, key_size);
2104 * mono_remote_class:
2105 * @domain: the application domain
2106 * @class_name: name of the remote class
2108 * Creates and initializes a MonoRemoteClass object for a remote type.
2112 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2114 MonoRemoteClass *rc;
2115 gpointer* key, *mp_key;
2117 key = create_remote_class_key (NULL, proxy_class);
2119 mono_domain_lock (domain);
2120 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2124 mono_domain_unlock (domain);
2128 mp_key = copy_remote_class_key (domain, key);
2132 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2133 rc = mono_domain_alloc (domain, sizeof(MonoRemoteClass) + sizeof(MonoClass*));
2134 rc->interface_count = 1;
2135 rc->interfaces [0] = proxy_class;
2136 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2138 rc = mono_domain_alloc (domain, sizeof(MonoRemoteClass));
2139 rc->interface_count = 0;
2140 rc->proxy_class = proxy_class;
2143 rc->default_vtable = NULL;
2144 rc->xdomain_vtable = NULL;
2145 rc->proxy_class_name = mono_string_to_utf8_mp (domain->mp, class_name);
2146 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2148 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2150 mono_domain_unlock (domain);
2155 * clone_remote_class:
2156 * Creates a copy of the remote_class, adding the provided class or interface
2158 static MonoRemoteClass*
2159 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2161 MonoRemoteClass *rc;
2162 gpointer* key, *mp_key;
2164 key = create_remote_class_key (remote_class, extra_class);
2165 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2171 mp_key = copy_remote_class_key (domain, key);
2175 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2177 rc = mono_domain_alloc (domain, sizeof(MonoRemoteClass) + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2178 rc->proxy_class = remote_class->proxy_class;
2179 rc->interface_count = remote_class->interface_count + 1;
2181 // Keep the list of interfaces sorted, since the hash key of
2182 // the remote class depends on this
2183 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2184 if (remote_class->interfaces [i] > extra_class && i == j)
2185 rc->interfaces [j++] = extra_class;
2186 rc->interfaces [j] = remote_class->interfaces [i];
2189 rc->interfaces [j] = extra_class;
2191 // Replace the old class. The interface array is the same
2192 rc = mono_domain_alloc (domain, sizeof(MonoRemoteClass) + sizeof(MonoClass*) * remote_class->interface_count);
2193 rc->proxy_class = extra_class;
2194 rc->interface_count = remote_class->interface_count;
2195 if (rc->interface_count > 0)
2196 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2199 rc->default_vtable = NULL;
2200 rc->xdomain_vtable = NULL;
2201 rc->proxy_class_name = remote_class->proxy_class_name;
2203 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2209 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2211 mono_domain_lock (domain);
2212 if (rp->target_domain_id != -1) {
2213 if (remote_class->xdomain_vtable == NULL)
2214 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2215 mono_domain_unlock (domain);
2216 return remote_class->xdomain_vtable;
2218 if (remote_class->default_vtable == NULL) {
2221 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2222 klass = mono_class_from_mono_type (type);
2223 if ((klass->is_com_object || (mono_defaults.com_object_class && klass == mono_defaults.com_object_class)) && !mono_class_vtable (mono_domain_get (), klass)->remote)
2224 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2226 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2229 mono_domain_unlock (domain);
2230 return remote_class->default_vtable;
2234 * mono_upgrade_remote_class:
2235 * @domain: the application domain
2236 * @tproxy: the proxy whose remote class has to be upgraded.
2237 * @klass: class to which the remote class can be casted.
2239 * Updates the vtable of the remote class by adding the necessary method slots
2240 * and interface offsets so it can be safely casted to klass. klass can be a
2241 * class or an interface.
2244 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2246 MonoTransparentProxy *tproxy;
2247 MonoRemoteClass *remote_class;
2248 gboolean redo_vtable;
2250 mono_domain_lock (domain);
2252 tproxy = (MonoTransparentProxy*) proxy_object;
2253 remote_class = tproxy->remote_class;
2255 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2258 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2259 if (remote_class->interfaces [i] == klass)
2260 redo_vtable = FALSE;
2263 redo_vtable = (remote_class->proxy_class != klass);
2267 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2268 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2271 mono_domain_unlock (domain);
2276 * mono_object_get_virtual_method:
2277 * @obj: object to operate on.
2280 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2281 * the instance of a callvirt of method.
2284 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2287 MonoMethod **vtable;
2289 MonoMethod *res = NULL;
2291 klass = mono_object_class (obj);
2292 if (klass == mono_defaults.transparent_proxy_class) {
2293 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2299 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2302 mono_class_setup_vtable (klass);
2303 vtable = klass->vtable;
2305 if (method->slot == -1) {
2306 /* method->slot might not be set for instances of generic methods */
2307 if (method->is_inflated) {
2308 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2309 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2312 g_assert_not_reached ();
2316 /* check method->slot is a valid index: perform isinstance? */
2317 if (method->slot != -1) {
2318 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2320 res = vtable [mono_class_interface_offset (klass, method->klass) + method->slot];
2322 res = vtable [method->slot];
2327 /* It may be an interface, abstract class method or generic method */
2328 if (!res || mono_method_signature (res)->generic_param_count)
2331 /* generic methods demand invoke_with_check */
2332 if (mono_method_signature (res)->generic_param_count)
2333 res = mono_marshal_get_remoting_invoke_with_check (res);
2335 res = mono_marshal_get_remoting_invoke (res);
2337 if (method->is_inflated && !res->is_inflated) {
2338 /* Have to inflate the result */
2339 res = mono_class_inflate_generic_method (res, &((MonoMethodInflated*)method)->context);
2349 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2351 g_error ("runtime invoke called on uninitialized runtime");
2355 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2358 * mono_runtime_invoke:
2359 * @method: method to invoke
2360 * @obJ: object instance
2361 * @params: arguments to the method
2362 * @exc: exception information.
2364 * Invokes the method represented by @method on the object @obj.
2366 * obj is the 'this' pointer, it should be NULL for static
2367 * methods, a MonoObject* for object instances and a pointer to
2368 * the value type for value types.
2370 * The params array contains the arguments to the method with the
2371 * same convention: MonoObject* pointers for object instances and
2372 * pointers to the value type otherwise.
2374 * From unmanaged code you'll usually use the
2375 * mono_runtime_invoke() variant.
2377 * Note that this function doesn't handle virtual methods for
2378 * you, it will exec the exact method you pass: we still need to
2379 * expose a function to lookup the derived class implementation
2380 * of a virtual method (there are examples of this in the code,
2383 * You can pass NULL as the exc argument if you don't want to
2384 * catch exceptions, otherwise, *exc will be set to the exception
2385 * thrown, if any. if an exception is thrown, you can't use the
2386 * MonoObject* result from the function.
2388 * If the method returns a value type, it is boxed in an object
2392 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2394 if (mono_runtime_get_no_exec ())
2395 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2397 return default_mono_runtime_invoke (method, obj, params, exc);
2401 * mono_method_get_unmanaged_thunk:
2402 * @method: method to generate a thunk for.
2404 * Returns an unmanaged->managed thunk that can be used to call
2405 * a managed method directly from C.
2407 * The thunk's C signature closely matches the managed signature:
2409 * C#: public bool Equals (object obj);
2410 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2411 * MonoObject*, MonoException**);
2413 * The 1st ("this") parameter must not be used with static methods:
2415 * C#: public static bool ReferenceEquals (object a, object b);
2416 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2419 * The last argument must be a non-null pointer of a MonoException* pointer.
2420 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2421 * exception has been thrown in managed code. Otherwise it will point
2422 * to the MonoException* caught by the thunk. In this case, the result of
2423 * the thunk is undefined:
2425 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2426 * MonoException *ex = NULL;
2427 * Equals func = mono_method_get_unmanaged_thunk (method);
2428 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2430 * // handle exception
2433 * The calling convention of the thunk matches the platform's default
2434 * convention. This means that under Windows, C declarations must
2435 * contain the __stdcall attribute:
2437 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2438 * MonoObject*, MonoException**);
2442 * Value type arguments and return values are treated as they were objects:
2444 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2445 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2447 * Arguments must be properly boxed upon trunk's invocation, while return
2448 * values must be unboxed.
2451 mono_method_get_unmanaged_thunk (MonoMethod *method)
2453 method = mono_marshal_get_thunk_invoke_wrapper (method);
2454 return mono_compile_method (method);
2458 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
2462 gpointer *p = (gpointer*)dest;
2469 case MONO_TYPE_BOOLEAN:
2471 case MONO_TYPE_U1: {
2472 guint8 *p = (guint8*)dest;
2473 *p = value ? *(guint8*)value : 0;
2478 case MONO_TYPE_CHAR: {
2479 guint16 *p = (guint16*)dest;
2480 *p = value ? *(guint16*)value : 0;
2483 #if SIZEOF_VOID_P == 4
2488 case MONO_TYPE_U4: {
2489 gint32 *p = (gint32*)dest;
2490 *p = value ? *(gint32*)value : 0;
2493 #if SIZEOF_VOID_P == 8
2498 case MONO_TYPE_U8: {
2499 gint64 *p = (gint64*)dest;
2500 *p = value ? *(gint64*)value : 0;
2503 case MONO_TYPE_R4: {
2504 float *p = (float*)dest;
2505 *p = value ? *(float*)value : 0;
2508 case MONO_TYPE_R8: {
2509 double *p = (double*)dest;
2510 *p = value ? *(double*)value : 0;
2513 case MONO_TYPE_STRING:
2514 case MONO_TYPE_SZARRAY:
2515 case MONO_TYPE_CLASS:
2516 case MONO_TYPE_OBJECT:
2517 case MONO_TYPE_ARRAY:
2518 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2520 case MONO_TYPE_FNPTR:
2521 case MONO_TYPE_PTR: {
2522 gpointer *p = (gpointer*)dest;
2523 *p = deref_pointer? *(gpointer*)value: value;
2526 case MONO_TYPE_VALUETYPE:
2527 /* note that 't' and 'type->type' can be different */
2528 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
2529 t = type->data.klass->enum_basetype->type;
2533 size = mono_class_value_size (mono_class_from_mono_type (type), NULL);
2535 memset (dest, 0, size);
2537 memcpy (dest, value, size);
2540 case MONO_TYPE_GENERICINST:
2541 t = type->data.generic_class->container_class->byval_arg.type;
2544 g_warning ("got type %x", type->type);
2545 g_assert_not_reached ();
2550 * mono_field_set_value:
2551 * @obj: Instance object
2552 * @field: MonoClassField describing the field to set
2553 * @value: The value to be set
2555 * Sets the value of the field described by @field in the object instance @obj
2556 * to the value passed in @value. This method should only be used for instance
2557 * fields. For static fields, use mono_field_static_set_value.
2559 * The value must be on the native format of the field type.
2562 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
2566 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2568 dest = (char*)obj + field->offset;
2569 set_value (field->type, dest, value, FALSE);
2573 * mono_field_static_set_value:
2574 * @field: MonoClassField describing the field to set
2575 * @value: The value to be set
2577 * Sets the value of the static field described by @field
2578 * to the value passed in @value.
2580 * The value must be on the native format of the field type.
2583 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
2587 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2588 /* you cant set a constant! */
2589 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
2591 dest = (char*)vt->data + field->offset;
2592 set_value (field->type, dest, value, FALSE);
2595 /* Used by the debugger */
2597 mono_vtable_get_static_field_data (MonoVTable *vt)
2603 * mono_field_get_value:
2604 * @obj: Object instance
2605 * @field: MonoClassField describing the field to fetch information from
2606 * @value: pointer to the location where the value will be stored
2608 * Use this routine to get the value of the field @field in the object
2611 * The pointer provided by value must be of the field type, for reference
2612 * types this is a MonoObject*, for value types its the actual pointer to
2617 * mono_field_get_value (obj, int_field, &i);
2620 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
2624 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2626 src = (char*)obj + field->offset;
2627 set_value (field->type, value, src, TRUE);
2631 * mono_field_get_value_object:
2632 * @domain: domain where the object will be created (if boxing)
2633 * @field: MonoClassField describing the field to fetch information from
2634 * @obj: The object instance for the field.
2636 * Returns: a new MonoObject with the value from the given field. If the
2637 * field represents a value type, the value is boxed.
2641 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
2645 MonoVTable *vtable = NULL;
2647 gboolean is_static = FALSE;
2648 gboolean is_ref = FALSE;
2650 switch (field->type->type) {
2651 case MONO_TYPE_STRING:
2652 case MONO_TYPE_OBJECT:
2653 case MONO_TYPE_CLASS:
2654 case MONO_TYPE_ARRAY:
2655 case MONO_TYPE_SZARRAY:
2660 case MONO_TYPE_BOOLEAN:
2663 case MONO_TYPE_CHAR:
2672 case MONO_TYPE_VALUETYPE:
2673 is_ref = field->type->byref;
2675 case MONO_TYPE_GENERICINST:
2676 is_ref = !field->type->data.generic_class->container_class->valuetype;
2679 g_error ("type 0x%x not handled in "
2680 "mono_field_get_value_object", field->type->type);
2684 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
2686 vtable = mono_class_vtable (domain, field->parent);
2687 if (!vtable->initialized)
2688 mono_runtime_class_init (vtable);
2693 mono_field_static_get_value (vtable, field, &o);
2695 mono_field_get_value (obj, field, &o);
2700 /* boxed value type */
2701 klass = mono_class_from_mono_type (field->type);
2702 o = mono_object_new (domain, klass);
2703 v = ((gchar *) o) + sizeof (MonoObject);
2705 mono_field_static_get_value (vtable, field, v);
2707 mono_field_get_value (obj, field, v);
2714 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
2717 const char *p = blob;
2718 mono_metadata_decode_blob_size (p, &p);
2721 case MONO_TYPE_BOOLEAN:
2724 *(guint8 *) value = *p;
2726 case MONO_TYPE_CHAR:
2729 *(guint16*) value = read16 (p);
2733 *(guint32*) value = read32 (p);
2737 *(guint64*) value = read64 (p);
2740 readr4 (p, (float*) value);
2743 readr8 (p, (double*) value);
2745 case MONO_TYPE_STRING:
2746 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
2748 case MONO_TYPE_CLASS:
2749 *(gpointer*) value = NULL;
2753 g_warning ("type 0x%02x should not be in constant table", type);
2759 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
2761 MonoTypeEnum def_type;
2764 data = mono_class_get_field_default_value (field, &def_type);
2765 mono_get_constant_value_from_blob (domain, def_type, data, value);
2769 * mono_field_static_get_value:
2770 * @vt: vtable to the object
2771 * @field: MonoClassField describing the field to fetch information from
2772 * @value: where the value is returned
2774 * Use this routine to get the value of the static field @field value.
2776 * The pointer provided by value must be of the field type, for reference
2777 * types this is a MonoObject*, for value types its the actual pointer to
2782 * mono_field_static_get_value (vt, int_field, &i);
2785 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
2789 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2791 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
2792 get_default_field_value (vt->domain, field, value);
2796 src = (char*)vt->data + field->offset;
2797 set_value (field->type, value, src, TRUE);
2801 * mono_property_set_value:
2802 * @prop: MonoProperty to set
2803 * @obj: instance object on which to act
2804 * @params: parameters to pass to the propery
2805 * @exc: optional exception
2807 * Invokes the property's set method with the given arguments on the
2808 * object instance obj (or NULL for static properties).
2810 * You can pass NULL as the exc argument if you don't want to
2811 * catch exceptions, otherwise, *exc will be set to the exception
2812 * thrown, if any. if an exception is thrown, you can't use the
2813 * MonoObject* result from the function.
2816 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
2818 default_mono_runtime_invoke (prop->set, obj, params, exc);
2822 * mono_property_get_value:
2823 * @prop: MonoProperty to fetch
2824 * @obj: instance object on which to act
2825 * @params: parameters to pass to the propery
2826 * @exc: optional exception
2828 * Invokes the property's get method with the given arguments on the
2829 * object instance obj (or NULL for static properties).
2831 * You can pass NULL as the exc argument if you don't want to
2832 * catch exceptions, otherwise, *exc will be set to the exception
2833 * thrown, if any. if an exception is thrown, you can't use the
2834 * MonoObject* result from the function.
2836 * Returns: the value from invoking the get method on the property.
2839 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
2841 return default_mono_runtime_invoke (prop->get, obj, params, exc);
2845 * mono_nullable_init:
2846 * @buf: The nullable structure to initialize.
2847 * @value: the value to initialize from
2848 * @klass: the type for the object
2850 * Initialize the nullable structure pointed to by @buf from @value which
2851 * should be a boxed value type. The size of @buf should be able to hold
2852 * as much data as the @klass->instance_size (which is the number of bytes
2853 * that will be copies).
2855 * Since Nullables have variable structure, we can not define a C
2856 * structure for them.
2859 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
2861 MonoClass *param_class = klass->cast_class;
2863 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
2864 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
2866 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
2868 memcpy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
2870 memset (buf + klass->fields [0].offset - sizeof (MonoObject), 0, mono_class_value_size (param_class, NULL));
2874 * mono_nullable_box:
2875 * @buf: The buffer representing the data to be boxed
2876 * @klass: the type to box it as.
2878 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
2882 mono_nullable_box (guint8 *buf, MonoClass *klass)
2884 MonoClass *param_class = klass->cast_class;
2886 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
2887 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
2889 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
2890 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
2891 memcpy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
2899 * mono_get_delegate_invoke:
2900 * @klass: The delegate class
2902 * Returns: the MonoMethod for the "Invoke" method in the delegate klass
2905 mono_get_delegate_invoke (MonoClass *klass)
2909 im = mono_class_get_method_from_name (klass, "Invoke", -1);
2916 * mono_runtime_delegate_invoke:
2917 * @delegate: pointer to a delegate object.
2918 * @params: parameters for the delegate.
2919 * @exc: Pointer to the exception result.
2921 * Invokes the delegate method @delegate with the parameters provided.
2923 * You can pass NULL as the exc argument if you don't want to
2924 * catch exceptions, otherwise, *exc will be set to the exception
2925 * thrown, if any. if an exception is thrown, you can't use the
2926 * MonoObject* result from the function.
2929 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
2933 im = mono_get_delegate_invoke (delegate->vtable->klass);
2936 return mono_runtime_invoke (im, delegate, params, exc);
2939 static char **main_args = NULL;
2940 static int num_main_args;
2943 * mono_runtime_get_main_args:
2945 * Returns: a MonoArray with the arguments passed to the main program
2948 mono_runtime_get_main_args (void)
2952 MonoDomain *domain = mono_domain_get ();
2957 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
2959 for (i = 0; i < num_main_args; ++i)
2960 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
2966 fire_process_exit_event (void)
2968 MonoClassField *field;
2969 MonoDomain *domain = mono_domain_get ();
2971 MonoObject *delegate, *exc;
2973 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "ProcessExit");
2976 if (domain != mono_get_root_domain ())
2979 delegate = *(MonoObject **)(((char *)domain->domain) + field->offset);
2980 if (delegate == NULL)
2985 mono_runtime_delegate_invoke (delegate, pa, &exc);
2989 * mono_runtime_run_main:
2990 * @method: the method to start the application with (usually Main)
2991 * @argc: number of arguments from the command line
2992 * @argv: array of strings from the command line
2993 * @exc: excetption results
2995 * Execute a standard Main() method (argc/argv contains the
2996 * executable name). This method also sets the command line argument value
2997 * needed by System.Environment.
3002 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3006 MonoArray *args = NULL;
3007 MonoDomain *domain = mono_domain_get ();
3008 gchar *utf8_fullpath;
3011 g_assert (method != NULL);
3013 mono_thread_set_main (mono_thread_current ());
3015 main_args = g_new0 (char*, argc);
3016 num_main_args = argc;
3018 if (!g_path_is_absolute (argv [0])) {
3019 gchar *basename = g_path_get_basename (argv [0]);
3020 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3024 utf8_fullpath = mono_utf8_from_external (fullpath);
3025 if(utf8_fullpath == NULL) {
3026 /* Printing the arg text will cause glib to
3027 * whinge about "Invalid UTF-8", but at least
3028 * its relevant, and shows the problem text
3031 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3032 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3039 utf8_fullpath = mono_utf8_from_external (argv[0]);
3040 if(utf8_fullpath == NULL) {
3041 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3042 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3047 main_args [0] = utf8_fullpath;
3049 for (i = 1; i < argc; ++i) {
3052 utf8_arg=mono_utf8_from_external (argv[i]);
3053 if(utf8_arg==NULL) {
3054 /* Ditto the comment about Invalid UTF-8 here */
3055 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3056 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3060 main_args [i] = utf8_arg;
3064 if (mono_method_signature (method)->param_count) {
3065 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3066 for (i = 0; i < argc; ++i) {
3067 /* The encodings should all work, given that
3068 * we've checked all these args for the
3071 gchar *str = mono_utf8_from_external (argv [i]);
3072 MonoString *arg = mono_string_new (domain, str);
3073 mono_array_setref (args, i, arg);
3077 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3080 mono_assembly_set_main (method->klass->image->assembly);
3082 result = mono_runtime_exec_main (method, args, exc);
3083 fire_process_exit_event ();
3087 /* Used in call_unhandled_exception_delegate */
3089 create_unhandled_exception_eventargs (MonoObject *exc)
3093 MonoMethod *method = NULL;
3094 MonoBoolean is_terminating = TRUE;
3097 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
3100 mono_class_init (klass);
3102 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
3103 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
3107 args [1] = &is_terminating;
3109 obj = mono_object_new (mono_domain_get (), klass);
3110 mono_runtime_invoke (method, obj, args, NULL);
3115 /* Used in mono_unhandled_exception */
3117 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
3118 MonoObject *e = NULL;
3121 pa [0] = domain->domain;
3122 pa [1] = create_unhandled_exception_eventargs (exc);
3123 mono_runtime_delegate_invoke (delegate, pa, &e);
3126 gchar *msg = mono_string_to_utf8 (((MonoException *) e)->message);
3127 g_warning ("exception inside UnhandledException handler: %s\n", msg);
3132 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANLED_POLICY_CURRENT;
3135 * mono_runtime_unhandled_exception_policy_set:
3136 * @policy: the new policy
3138 * This is a VM internal routine.
3140 * Sets the runtime policy for handling unhandled exceptions.
3143 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
3144 runtime_unhandled_exception_policy = policy;
3148 * mono_runtime_unhandled_exception_policy_get:
3150 * This is a VM internal routine.
3152 * Gets the runtime policy for handling unhandled exceptions.
3154 MonoRuntimeUnhandledExceptionPolicy
3155 mono_runtime_unhandled_exception_policy_get (void) {
3156 return runtime_unhandled_exception_policy;
3160 * mono_unhandled_exception:
3161 * @exc: exception thrown
3163 * This is a VM internal routine.
3165 * We call this function when we detect an unhandled exception
3166 * in the default domain.
3168 * It invokes the * UnhandledException event in AppDomain or prints
3169 * a warning to the console
3172 mono_unhandled_exception (MonoObject *exc)
3174 MonoDomain *current_domain = mono_domain_get ();
3175 MonoDomain *root_domain = mono_get_root_domain ();
3176 MonoClassField *field;
3177 MonoObject *current_appdomain_delegate;
3178 MonoObject *root_appdomain_delegate;
3180 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
3181 "UnhandledException");
3184 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
3185 gboolean abort_process = (mono_thread_current () == main_thread) ||
3186 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANLED_POLICY_CURRENT);
3187 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
3188 if (current_domain != root_domain && (mono_framework_version () >= 2)) {
3189 current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
3191 current_appdomain_delegate = NULL;
3194 /* set exitcode only if we will abort the process */
3196 mono_environment_exitcode_set (1);
3197 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
3198 mono_print_unhandled_exception (exc);
3200 if (root_appdomain_delegate) {
3201 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
3203 if (current_appdomain_delegate) {
3204 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
3211 * Launch a new thread to execute a function
3213 * main_func is called back from the thread with main_args as the
3214 * parameter. The callback function is expected to start Main()
3215 * eventually. This function then waits for all managed threads to
3217 * It is not necesseray anymore to execute managed code in a subthread,
3218 * so this function should not be used anymore by default: just
3219 * execute the code and then call mono_thread_manage ().
3222 mono_runtime_exec_managed_code (MonoDomain *domain,
3223 MonoMainThreadFunc main_func,
3226 mono_thread_create (domain, main_func, main_args);
3228 mono_thread_manage ();
3232 * Execute a standard Main() method (args doesn't contain the
3236 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
3241 MonoCustomAttrInfo* cinfo;
3242 gboolean has_stathread_attribute;
3243 MonoThread* thread = mono_thread_current ();
3249 domain = mono_object_domain (args);
3250 if (!domain->entry_assembly) {
3252 MonoAssembly *assembly;
3254 assembly = method->klass->image->assembly;
3255 domain->entry_assembly = assembly;
3256 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
3258 str = g_strconcat (assembly->image->name, ".config", NULL);
3259 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
3263 cinfo = mono_custom_attrs_from_method (method);
3265 static MonoClass *stathread_attribute = NULL;
3266 if (!stathread_attribute)
3267 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
3268 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
3270 mono_custom_attrs_free (cinfo);
3272 has_stathread_attribute = FALSE;
3274 if (has_stathread_attribute) {
3275 thread->apartment_state = ThreadApartmentState_STA;
3276 } else if (mono_framework_version () == 1) {
3277 thread->apartment_state = ThreadApartmentState_Unknown;
3279 thread->apartment_state = ThreadApartmentState_MTA;
3281 mono_thread_init_apartment_state ();
3283 mono_debugger_event (MONO_DEBUGGER_EVENT_REACHED_MAIN, 0, 0);
3285 /* FIXME: check signature of method */
3286 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
3288 res = mono_runtime_invoke (method, NULL, pa, exc);
3290 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
3294 mono_environment_exitcode_set (rval);
3296 mono_runtime_invoke (method, NULL, pa, exc);
3300 /* If the return type of Main is void, only
3301 * set the exitcode if an exception was thrown
3302 * (we don't want to blow away an
3303 * explicitly-set exit code)
3306 mono_environment_exitcode_set (rval);
3310 mono_debugger_event (MONO_DEBUGGER_EVENT_MAIN_EXITED, (guint64) (gsize) rval, 0);
3316 * mono_install_runtime_invoke:
3317 * @func: Function to install
3319 * This is a VM internal routine
3322 mono_install_runtime_invoke (MonoInvokeFunc func)
3324 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
3329 * mono_runtime_invoke_array:
3330 * @method: method to invoke
3331 * @obJ: object instance
3332 * @params: arguments to the method
3333 * @exc: exception information.
3335 * Invokes the method represented by @method on the object @obj.
3337 * obj is the 'this' pointer, it should be NULL for static
3338 * methods, a MonoObject* for object instances and a pointer to
3339 * the value type for value types.
3341 * The params array contains the arguments to the method with the
3342 * same convention: MonoObject* pointers for object instances and
3343 * pointers to the value type otherwise. The _invoke_array
3344 * variant takes a C# object[] as the params argument (MonoArray
3345 * *params): in this case the value types are boxed inside the
3346 * respective reference representation.
3348 * From unmanaged code you'll usually use the
3349 * mono_runtime_invoke() variant.
3351 * Note that this function doesn't handle virtual methods for
3352 * you, it will exec the exact method you pass: we still need to
3353 * expose a function to lookup the derived class implementation
3354 * of a virtual method (there are examples of this in the code,
3357 * You can pass NULL as the exc argument if you don't want to
3358 * catch exceptions, otherwise, *exc will be set to the exception
3359 * thrown, if any. if an exception is thrown, you can't use the
3360 * MonoObject* result from the function.
3362 * If the method returns a value type, it is boxed in an object
3366 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
3369 MonoMethodSignature *sig = mono_method_signature (method);
3370 gpointer *pa = NULL;
3373 if (NULL != params) {
3374 pa = alloca (sizeof (gpointer) * mono_array_length (params));
3375 for (i = 0; i < mono_array_length (params); i++) {
3376 MonoType *t = sig->params [i];
3382 case MONO_TYPE_BOOLEAN:
3385 case MONO_TYPE_CHAR:
3394 case MONO_TYPE_VALUETYPE:
3395 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
3398 g_assert_not_reached ();
3399 /* The runtime invoke wrapper needs the original boxed vtype */
3400 pa [i] = mono_array_get (params, MonoObject*, i);
3402 /* MS seems to create the objects if a null is passed in */
3403 if (!mono_array_get (params, MonoObject*, i))
3404 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
3408 * We can't pass the unboxed vtype byref to the callee, since
3409 * that would mean the callee would be able to modify boxed
3410 * primitive types. So we (and MS) make a copy of the boxed
3411 * object, pass that to the callee, and replace the original
3412 * boxed object in the arg array with the copy.
3414 MonoObject *orig = mono_array_get (params, MonoObject*, i);
3415 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
3416 mono_array_setref (params, i, copy);
3419 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
3422 case MONO_TYPE_STRING:
3423 case MONO_TYPE_OBJECT:
3424 case MONO_TYPE_CLASS:
3425 case MONO_TYPE_ARRAY:
3426 case MONO_TYPE_SZARRAY:
3428 pa [i] = mono_array_addr (params, MonoObject*, i);
3429 // FIXME: I need to check this code path
3431 pa [i] = mono_array_get (params, MonoObject*, i);
3433 case MONO_TYPE_GENERICINST:
3435 t = &t->data.generic_class->container_class->this_arg;
3437 t = &t->data.generic_class->container_class->byval_arg;
3440 g_error ("type 0x%x not handled in ves_icall_InternalInvoke", sig->params [i]->type);
3445 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
3448 if (mono_class_is_nullable (method->klass)) {
3449 /* Need to create a boxed vtype instead */
3455 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
3459 obj = mono_object_new (mono_domain_get (), method->klass);
3460 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
3461 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
3463 if (method->klass->valuetype)
3464 o = mono_object_unbox (obj);
3467 } else if (method->klass->valuetype) {
3468 obj = mono_value_box (mono_domain_get (), method->klass, obj);
3471 mono_runtime_invoke (method, o, pa, exc);
3474 if (mono_class_is_nullable (method->klass)) {
3475 MonoObject *nullable;
3477 /* Convert the unboxed vtype into a Nullable structure */
3478 nullable = mono_object_new (mono_domain_get (), method->klass);
3480 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
3481 obj = mono_object_unbox (nullable);
3484 /* obj must be already unboxed if needed */
3485 return mono_runtime_invoke (method, obj, pa, exc);
3490 arith_overflow (void)
3492 mono_raise_exception (mono_get_exception_overflow ());
3496 * mono_object_allocate:
3497 * @size: number of bytes to allocate
3499 * This is a very simplistic routine until we have our GC-aware
3502 * Returns: an allocated object of size @size, or NULL on failure.
3504 static inline void *
3505 mono_object_allocate (size_t size, MonoVTable *vtable)
3508 mono_stats.new_object_count++;
3509 ALLOC_OBJECT (o, vtable, size);
3515 * mono_object_allocate_ptrfree:
3516 * @size: number of bytes to allocate
3518 * Note that the memory allocated is not zeroed.
3519 * Returns: an allocated object of size @size, or NULL on failure.
3521 static inline void *
3522 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
3525 mono_stats.new_object_count++;
3526 ALLOC_PTRFREE (o, vtable, size);
3530 static inline void *
3531 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
3534 ALLOC_TYPED (o, size, vtable);
3535 mono_stats.new_object_count++;
3542 * @klass: the class of the object that we want to create
3544 * Returns: a newly created object whose definition is
3545 * looked up using @klass. This will not invoke any constructors,
3546 * so the consumer of this routine has to invoke any constructors on
3547 * its own to initialize the object.
3550 mono_object_new (MonoDomain *domain, MonoClass *klass)
3552 MONO_ARCH_SAVE_REGS;
3553 return mono_object_new_specific (mono_class_vtable (domain, klass));
3557 * mono_object_new_specific:
3558 * @vtable: the vtable of the object that we want to create
3560 * Returns: A newly created object with class and domain specified
3564 mono_object_new_specific (MonoVTable *vtable)
3568 MONO_ARCH_SAVE_REGS;
3570 /* check for is_com_object for COM Interop */
3571 if (vtable->remote || vtable->klass->is_com_object)
3574 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
3577 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
3580 mono_class_init (klass);
3582 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
3584 vtable->domain->create_proxy_for_type_method = im;
3587 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
3589 o = mono_runtime_invoke (im, NULL, pa, NULL);
3590 if (o != NULL) return o;
3593 return mono_object_new_alloc_specific (vtable);
3597 mono_object_new_alloc_specific (MonoVTable *vtable)
3601 if (!vtable->klass->has_references) {
3602 o = mono_object_new_ptrfree (vtable);
3603 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3604 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
3606 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
3607 o = mono_object_allocate (vtable->klass->instance_size, vtable);
3609 if (G_UNLIKELY (vtable->klass->has_finalize))
3610 mono_object_register_finalizer (o);
3612 if (G_UNLIKELY (profile_allocs))
3613 mono_profiler_allocation (o, vtable->klass);
3618 mono_object_new_fast (MonoVTable *vtable)
3621 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
3626 mono_object_new_ptrfree (MonoVTable *vtable)
3629 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
3630 #if NEED_TO_ZERO_PTRFREE
3631 /* an inline memset is much faster for the common vcase of small objects
3632 * note we assume the allocated size is a multiple of sizeof (void*).
3634 if (vtable->klass->instance_size < 128) {
3636 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
3637 p = (gpointer*)((char*)obj + sizeof (MonoObject));
3643 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
3650 mono_object_new_ptrfree_box (MonoVTable *vtable)
3653 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
3654 /* the object will be boxed right away, no need to memzero it */
3659 * mono_class_get_allocation_ftn:
3661 * @for_box: the object will be used for boxing
3662 * @pass_size_in_words:
3664 * Return the allocation function appropriate for the given class.
3668 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
3670 *pass_size_in_words = FALSE;
3672 if (!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
3673 profile_allocs = FALSE;
3675 if (vtable->klass->has_finalize || vtable->klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
3676 return mono_object_new_specific;
3678 if (!vtable->klass->has_references) {
3679 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
3681 return mono_object_new_ptrfree_box;
3682 return mono_object_new_ptrfree;
3685 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3687 return mono_object_new_fast;
3690 * FIXME: This is actually slower than mono_object_new_fast, because
3691 * of the overhead of parameter passing.
3694 *pass_size_in_words = TRUE;
3695 #ifdef GC_REDIRECT_TO_LOCAL
3696 return GC_local_gcj_fast_malloc;
3698 return GC_gcj_fast_malloc;
3703 return mono_object_new_specific;
3707 * mono_object_new_from_token:
3708 * @image: Context where the type_token is hosted
3709 * @token: a token of the type that we want to create
3711 * Returns: A newly created object whose definition is
3712 * looked up using @token in the @image image
3715 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
3719 class = mono_class_get (image, token);
3721 return mono_object_new (domain, class);
3726 * mono_object_clone:
3727 * @obj: the object to clone
3729 * Returns: A newly created object who is a shallow copy of @obj
3732 mono_object_clone (MonoObject *obj)
3737 size = obj->vtable->klass->instance_size;
3738 o = mono_object_allocate (size, obj->vtable);
3739 /* do not copy the sync state */
3740 memcpy ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
3743 if (obj->vtable->klass->has_references)
3744 mono_gc_wbarrier_object (o);
3746 if (G_UNLIKELY (profile_allocs))
3747 mono_profiler_allocation (o, obj->vtable->klass);
3749 if (obj->vtable->klass->has_finalize)
3750 mono_object_register_finalizer (o);
3755 * mono_array_full_copy:
3756 * @src: source array to copy
3757 * @dest: destination array
3759 * Copies the content of one array to another with exactly the same type and size.
3762 mono_array_full_copy (MonoArray *src, MonoArray *dest)
3764 mono_array_size_t size;
3765 MonoClass *klass = src->obj.vtable->klass;
3767 MONO_ARCH_SAVE_REGS;
3769 g_assert (klass == dest->obj.vtable->klass);
3771 size = mono_array_length (src);
3772 g_assert (size == mono_array_length (dest));
3773 size *= mono_array_element_size (klass);
3775 if (klass->element_class->valuetype) {
3776 if (klass->element_class->has_references)
3777 mono_value_copy_array (dest, 0, src, mono_array_length (src));
3779 memcpy (&dest->vector, &src->vector, size);
3781 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
3784 memcpy (&dest->vector, &src->vector, size);
3789 * mono_array_clone_in_domain:
3790 * @domain: the domain in which the array will be cloned into
3791 * @array: the array to clone
3793 * This routine returns a copy of the array that is hosted on the
3794 * specified MonoDomain.
3797 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
3800 mono_array_size_t size, i;
3801 mono_array_size_t *sizes;
3802 MonoClass *klass = array->obj.vtable->klass;
3804 MONO_ARCH_SAVE_REGS;
3806 if (array->bounds == NULL) {
3807 size = mono_array_length (array);
3808 o = mono_array_new_full (domain, klass, &size, NULL);
3810 size *= mono_array_element_size (klass);
3812 if (klass->element_class->valuetype) {
3813 if (klass->element_class->has_references)
3814 mono_value_copy_array (o, 0, array, mono_array_length (array));
3816 memcpy (&o->vector, &array->vector, size);
3818 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
3821 memcpy (&o->vector, &array->vector, size);
3826 sizes = alloca (klass->rank * sizeof(mono_array_size_t) * 2);
3827 size = mono_array_element_size (klass);
3828 for (i = 0; i < klass->rank; ++i) {
3829 sizes [i] = array->bounds [i].length;
3830 size *= array->bounds [i].length;
3831 sizes [i + klass->rank] = array->bounds [i].lower_bound;
3833 o = mono_array_new_full (domain, klass, sizes, sizes + klass->rank);
3835 if (klass->element_class->valuetype) {
3836 if (klass->element_class->has_references)
3837 mono_value_copy_array (o, 0, array, mono_array_length (array));
3839 memcpy (&o->vector, &array->vector, size);
3841 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
3844 memcpy (&o->vector, &array->vector, size);
3852 * @array: the array to clone
3854 * Returns: A newly created array who is a shallow copy of @array
3857 mono_array_clone (MonoArray *array)
3859 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
3862 /* helper macros to check for overflow when calculating the size of arrays */
3863 #ifdef MONO_BIG_ARRAYS
3864 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
3865 #define MYGUINT_MAX MYGUINT64_MAX
3866 #define CHECK_ADD_OVERFLOW_UN(a,b) \
3867 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
3868 #define CHECK_MUL_OVERFLOW_UN(a,b) \
3869 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
3870 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
3872 #define MYGUINT32_MAX 4294967295U
3873 #define MYGUINT_MAX MYGUINT32_MAX
3874 #define CHECK_ADD_OVERFLOW_UN(a,b) \
3875 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
3876 #define CHECK_MUL_OVERFLOW_UN(a,b) \
3877 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
3878 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
3882 * mono_array_new_full:
3883 * @domain: domain where the object is created
3884 * @array_class: array class
3885 * @lengths: lengths for each dimension in the array
3886 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
3888 * This routine creates a new array objects with the given dimensions,
3889 * lower bounds and type.
3892 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, mono_array_size_t *lengths, mono_array_size_t *lower_bounds)
3894 mono_array_size_t byte_len, len, bounds_size;
3900 if (!array_class->inited)
3901 mono_class_init (array_class);
3903 byte_len = mono_array_element_size (array_class);
3906 /* A single dimensional array with a 0 lower bound is the same as an szarray */
3907 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
3909 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
3913 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
3915 for (i = 0; i < array_class->rank; ++i) {
3916 if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
3918 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
3919 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3924 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
3925 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3927 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
3928 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3929 byte_len += sizeof (MonoArray);
3932 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
3933 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3934 byte_len = (byte_len + 3) & ~3;
3935 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
3936 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3937 byte_len += bounds_size;
3940 * Following three lines almost taken from mono_object_new ():
3941 * they need to be kept in sync.
3943 vtable = mono_class_vtable (domain, array_class);
3944 if (!array_class->has_references) {
3945 o = mono_object_allocate_ptrfree (byte_len, vtable);
3946 #if NEED_TO_ZERO_PTRFREE
3947 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
3949 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3950 o = mono_object_allocate_spec (byte_len, vtable);
3952 o = mono_object_allocate (byte_len, vtable);
3955 array = (MonoArray*)o;
3956 array->max_length = len;
3959 MonoArrayBounds *bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
3960 array->bounds = bounds;
3961 for (i = 0; i < array_class->rank; ++i) {
3962 bounds [i].length = lengths [i];
3964 bounds [i].lower_bound = lower_bounds [i];
3968 if (G_UNLIKELY (profile_allocs))
3969 mono_profiler_allocation (o, array_class);
3976 * @domain: domain where the object is created
3977 * @eclass: element class
3978 * @n: number of array elements
3980 * This routine creates a new szarray with @n elements of type @eclass.
3983 mono_array_new (MonoDomain *domain, MonoClass *eclass, mono_array_size_t n)
3987 MONO_ARCH_SAVE_REGS;
3989 ac = mono_array_class_get (eclass, 1);
3992 return mono_array_new_specific (mono_class_vtable (domain, ac), n);
3996 * mono_array_new_specific:
3997 * @vtable: a vtable in the appropriate domain for an initialized class
3998 * @n: number of array elements
4000 * This routine is a fast alternative to mono_array_new() for code which
4001 * can be sure about the domain it operates in.
4004 mono_array_new_specific (MonoVTable *vtable, mono_array_size_t n)
4008 guint32 byte_len, elem_size;
4010 MONO_ARCH_SAVE_REGS;
4012 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
4017 elem_size = mono_array_element_size (vtable->klass);
4018 if (CHECK_MUL_OVERFLOW_UN (n, elem_size)) {
4019 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4022 byte_len = n * elem_size;
4023 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray))) {
4024 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4027 byte_len += sizeof (MonoArray);
4028 if (!vtable->klass->has_references) {
4029 o = mono_object_allocate_ptrfree (byte_len, vtable);
4030 #if NEED_TO_ZERO_PTRFREE
4031 ((MonoArray*)o)->bounds = NULL;
4032 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4034 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4035 o = mono_object_allocate_spec (byte_len, vtable);
4037 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4038 o = mono_object_allocate (byte_len, vtable);
4041 ao = (MonoArray *)o;
4043 if (G_UNLIKELY (profile_allocs))
4044 mono_profiler_allocation (o, vtable->klass);
4050 * mono_string_new_utf16:
4051 * @text: a pointer to an utf16 string
4052 * @len: the length of the string
4054 * Returns: A newly created string object which contains @text.
4057 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
4061 s = mono_string_new_size (domain, len);
4062 g_assert (s != NULL);
4064 memcpy (mono_string_chars (s), text, len * 2);
4070 * mono_string_new_size:
4071 * @text: a pointer to an utf16 string
4072 * @len: the length of the string
4074 * Returns: A newly created string object of @len
4077 mono_string_new_size (MonoDomain *domain, gint32 len)
4081 size_t size = (sizeof (MonoString) + ((len + 1) * 2));
4083 /* overflow ? can't fit it, can't allocate it! */
4085 mono_gc_out_of_memory (-1);
4087 vtable = mono_class_vtable (domain, mono_defaults.string_class);
4089 s = mono_object_allocate_ptrfree (size, vtable);
4092 #if NEED_TO_ZERO_PTRFREE
4095 if (G_UNLIKELY (profile_allocs))
4096 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
4102 * mono_string_new_len:
4103 * @text: a pointer to an utf8 string
4104 * @length: number of bytes in @text to consider
4106 * Returns: A newly created string object which contains @text.
4109 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
4111 GError *error = NULL;
4112 MonoString *o = NULL;
4114 glong items_written;
4116 ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
4119 o = mono_string_new_utf16 (domain, ut, items_written);
4121 g_error_free (error);
4130 * @text: a pointer to an utf8 string
4132 * Returns: A newly created string object which contains @text.
4135 mono_string_new (MonoDomain *domain, const char *text)
4137 GError *error = NULL;
4138 MonoString *o = NULL;
4140 glong items_written;
4145 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
4148 o = mono_string_new_utf16 (domain, ut, items_written);
4150 g_error_free (error);
4153 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
4158 MonoString *o = NULL;
4160 if (!g_utf8_validate (text, -1, &end))
4163 len = g_utf8_strlen (text, -1);
4164 o = mono_string_new_size (domain, len);
4165 str = mono_string_chars (o);
4167 while (text < end) {
4168 *str++ = g_utf8_get_char (text);
4169 text = g_utf8_next_char (text);
4176 * mono_string_new_wrapper:
4177 * @text: pointer to utf8 characters.
4179 * Helper function to create a string object from @text in the current domain.
4182 mono_string_new_wrapper (const char *text)
4184 MonoDomain *domain = mono_domain_get ();
4186 MONO_ARCH_SAVE_REGS;
4189 return mono_string_new (domain, text);
4196 * @class: the class of the value
4197 * @value: a pointer to the unboxed data
4199 * Returns: A newly created object which contains @value.
4202 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
4208 g_assert (class->valuetype);
4209 if (mono_class_is_nullable (class))
4210 return mono_nullable_box (value, class);
4212 vtable = mono_class_vtable (domain, class);
4213 size = mono_class_instance_size (class);
4214 res = mono_object_new_alloc_specific (vtable);
4215 if (G_UNLIKELY (profile_allocs))
4216 mono_profiler_allocation (res, class);
4218 size = size - sizeof (MonoObject);
4221 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
4224 #if NO_UNALIGNED_ACCESS
4225 memcpy ((char *)res + sizeof (MonoObject), value, size);
4229 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
4232 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
4235 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
4238 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
4241 memcpy ((char *)res + sizeof (MonoObject), value, size);
4244 if (class->has_finalize)
4245 mono_object_register_finalizer (res);
4251 * @dest: destination pointer
4252 * @src: source pointer
4253 * @klass: a valuetype class
4255 * Copy a valuetype from @src to @dest. This function must be used
4256 * when @klass contains references fields.
4259 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
4261 int size = mono_class_value_size (klass, NULL);
4262 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
4263 memcpy (dest, src, size);
4267 * mono_value_copy_array:
4268 * @dest: destination array
4269 * @dest_idx: index in the @dest array
4270 * @src: source pointer
4271 * @count: number of items
4273 * Copy @count valuetype items from @src to @dest. This function must be used
4274 * when @klass contains references fields.
4275 * Overlap is handled.
4278 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
4280 int size = mono_array_element_size (dest->obj.vtable->klass);
4281 char *d = mono_array_addr_with_size (dest, size, dest_idx);
4282 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
4283 memmove (d, src, size * count);
4287 * mono_object_get_domain:
4288 * @obj: object to query
4290 * Returns: the MonoDomain where the object is hosted
4293 mono_object_get_domain (MonoObject *obj)
4295 return mono_object_domain (obj);
4299 * mono_object_get_class:
4300 * @obj: object to query
4302 * Returns: the MonOClass of the object.
4305 mono_object_get_class (MonoObject *obj)
4307 return mono_object_class (obj);
4310 * mono_object_get_size:
4311 * @o: object to query
4313 * Returns: the size, in bytes, of @o
4316 mono_object_get_size (MonoObject* o)
4318 MonoClass* klass = mono_object_class (o);
4319 if (klass == mono_defaults.string_class) {
4320 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
4321 } else if (o->vtable->rank) {
4322 MonoArray *array = (MonoArray*)o;
4323 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
4324 if (array->bounds) {
4327 size += sizeof (MonoArrayBounds) * o->vtable->rank;
4331 return mono_class_instance_size (klass);
4336 * mono_object_unbox:
4337 * @obj: object to unbox
4339 * Returns: a pointer to the start of the valuetype boxed in this
4342 * This method will assert if the object passed is not a valuetype.
4345 mono_object_unbox (MonoObject *obj)
4347 /* add assert for valuetypes? */
4348 g_assert (obj->vtable->klass->valuetype);
4349 return ((char*)obj) + sizeof (MonoObject);
4353 * mono_object_isinst:
4355 * @klass: a pointer to a class
4357 * Returns: @obj if @obj is derived from @klass
4360 mono_object_isinst (MonoObject *obj, MonoClass *klass)
4363 mono_class_init (klass);
4365 if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE)
4366 return mono_object_isinst_mbyref (obj, klass);
4371 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
4375 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
4384 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4385 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
4389 MonoClass *oklass = vt->klass;
4390 if ((oklass == mono_defaults.transparent_proxy_class))
4391 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
4393 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
4397 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
4399 MonoDomain *domain = mono_domain_get ();
4401 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
4402 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
4403 MonoMethod *im = NULL;
4406 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
4407 im = mono_object_get_virtual_method (rp, im);
4410 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
4413 res = mono_runtime_invoke (im, rp, pa, NULL);
4415 if (*(MonoBoolean *) mono_object_unbox(res)) {
4416 /* Update the vtable of the remote type, so it can safely cast to this new type */
4417 mono_upgrade_remote_class (domain, obj, klass);
4426 * mono_object_castclass_mbyref:
4428 * @klass: a pointer to a class
4430 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
4433 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
4435 if (!obj) return NULL;
4436 if (mono_object_isinst_mbyref (obj, klass)) return obj;
4438 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
4440 "InvalidCastException"));
4445 MonoDomain *orig_domain;
4451 str_lookup (MonoDomain *domain, gpointer user_data)
4453 LDStrInfo *info = user_data;
4454 if (info->res || domain == info->orig_domain)
4456 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
4462 mono_string_get_pinned (MonoString *str)
4466 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
4467 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
4468 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
4469 news->length = mono_string_length (str);
4474 #define mono_string_get_pinned(str) (str)
4478 mono_string_is_interned_lookup (MonoString *str, int insert)
4480 MonoGHashTable *ldstr_table;
4484 domain = ((MonoObject *)str)->vtable->domain;
4485 ldstr_table = domain->ldstr_table;
4487 if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
4492 str = mono_string_get_pinned (str);
4493 mono_g_hash_table_insert (ldstr_table, str, str);
4497 LDStrInfo ldstr_info;
4498 ldstr_info.orig_domain = domain;
4499 ldstr_info.ins = str;
4500 ldstr_info.res = NULL;
4502 mono_domain_foreach (str_lookup, &ldstr_info);
4503 if (ldstr_info.res) {
4505 * the string was already interned in some other domain:
4506 * intern it in the current one as well.
4508 mono_g_hash_table_insert (ldstr_table, str, str);
4518 * mono_string_is_interned:
4519 * @o: String to probe
4521 * Returns whether the string has been interned.
4524 mono_string_is_interned (MonoString *o)
4526 return mono_string_is_interned_lookup (o, FALSE);
4530 * mono_string_intern:
4531 * @o: String to intern
4533 * Interns the string passed.
4534 * Returns: The interned string.
4537 mono_string_intern (MonoString *str)
4539 return mono_string_is_interned_lookup (str, TRUE);
4544 * @domain: the domain where the string will be used.
4545 * @image: a metadata context
4546 * @idx: index into the user string table.
4548 * Implementation for the ldstr opcode.
4549 * Returns: a loaded string from the @image/@idx combination.
4552 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
4554 MONO_ARCH_SAVE_REGS;
4557 return mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
4559 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
4563 * mono_ldstr_metadata_sig
4564 * @domain: the domain for the string
4565 * @sig: the signature of a metadata string
4567 * Returns: a MonoString for a string stored in the metadata
4570 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
4572 const char *str = sig;
4573 MonoString *o, *interned;
4576 len2 = mono_metadata_decode_blob_size (str, &str);
4579 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
4580 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
4583 guint16 *p2 = (guint16*)mono_string_chars (o);
4584 for (i = 0; i < len2; ++i) {
4585 *p2 = GUINT16_FROM_LE (*p2);
4591 if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
4593 /* o will get garbage collected */
4597 o = mono_string_get_pinned (o);
4598 mono_g_hash_table_insert (domain->ldstr_table, o, o);
4605 * mono_string_to_utf8:
4606 * @s: a System.String
4608 * Return the UTF8 representation for @s.
4609 * the resulting buffer nedds to be freed with g_free().
4612 mono_string_to_utf8 (MonoString *s)
4616 GError *error = NULL;
4622 return g_strdup ("");
4624 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &error);
4626 MonoException *exc = mono_get_exception_argument ("string", error->message);
4627 g_error_free (error);
4628 mono_raise_exception(exc);
4630 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
4631 if (s->length > written) {
4632 /* allocate the total length and copy the part of the string that has been converted */
4633 char *as2 = g_malloc0 (s->length);
4634 memcpy (as2, as, written);
4643 * mono_string_to_utf16:
4646 * Return an null-terminated array of the utf-16 chars
4647 * contained in @s. The result must be freed with g_free().
4648 * This is a temporary helper until our string implementation
4649 * is reworked to always include the null terminating char.
4652 mono_string_to_utf16 (MonoString *s)
4659 as = g_malloc ((s->length * 2) + 2);
4660 as [(s->length * 2)] = '\0';
4661 as [(s->length * 2) + 1] = '\0';
4664 return (gunichar2 *)(as);
4667 memcpy (as, mono_string_chars(s), s->length * 2);
4668 return (gunichar2 *)(as);
4672 * mono_string_from_utf16:
4673 * @data: the UTF16 string (LPWSTR) to convert
4675 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
4677 * Returns: a MonoString.
4680 mono_string_from_utf16 (gunichar2 *data)
4682 MonoDomain *domain = mono_domain_get ();
4688 while (data [len]) len++;
4690 return mono_string_new_utf16 (domain, data, len);
4694 * mono_string_to_utf8_mp:
4695 * @s: a System.String
4697 * Same as mono_string_to_utf8, but allocate the string from a mempool.
4700 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s)
4702 char *r = mono_string_to_utf8 (s);
4709 len = strlen (r) + 1;
4710 mp_s = mono_mempool_alloc (mp, len);
4711 memcpy (mp_s, r, len);
4719 default_ex_handler (MonoException *ex)
4721 MonoObject *o = (MonoObject*)ex;
4722 g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
4726 static MonoExceptionFunc ex_handler = default_ex_handler;
4729 * mono_install_handler:
4730 * @func: exception handler
4732 * This is an internal JIT routine used to install the handler for exceptions
4736 mono_install_handler (MonoExceptionFunc func)
4738 ex_handler = func? func: default_ex_handler;
4742 * mono_raise_exception:
4743 * @ex: exception object
4745 * Signal the runtime that the exception @ex has been raised in unmanaged code.
4748 mono_raise_exception (MonoException *ex)
4751 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
4752 * that will cause gcc to omit the function epilog, causing problems when
4753 * the JIT tries to walk the stack, since the return address on the stack
4754 * will point into the next function in the executable, not this one.
4757 if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class)
4758 MONO_OBJECT_SETREF (mono_thread_current (), abort_exc, ex);
4764 * mono_wait_handle_new:
4765 * @domain: Domain where the object will be created
4766 * @handle: Handle for the wait handle
4768 * Returns: A new MonoWaitHandle created in the given domain for the given handle
4771 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
4773 MonoWaitHandle *res;
4774 gpointer params [1];
4775 static MonoMethod *handle_set;
4777 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.waithandle_class);
4779 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
4781 handle_set = mono_class_get_property_from_name (mono_defaults.waithandle_class, "Handle")->set;
4783 params [0] = &handle;
4784 mono_runtime_invoke (handle_set, res, params, NULL);
4790 mono_wait_handle_get_handle (MonoWaitHandle *handle)
4792 static MonoClassField *f_os_handle;
4793 static MonoClassField *f_safe_handle;
4795 if (!f_os_handle && !f_safe_handle) {
4796 f_os_handle = mono_class_get_field_from_name (mono_defaults.waithandle_class, "os_handle");
4797 f_safe_handle = mono_class_get_field_from_name (mono_defaults.waithandle_class, "safe_wait_handle");
4802 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
4806 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
4812 * mono_async_result_new:
4813 * @domain:domain where the object will be created.
4814 * @handle: wait handle.
4815 * @state: state to pass to AsyncResult
4816 * @data: C closure data.
4818 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
4819 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
4823 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
4825 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
4826 MonoMethod *method = mono_get_context_capture_method ();
4828 /* we must capture the execution context from the original thread */
4830 MONO_OBJECT_SETREF (res, execution_context, mono_runtime_invoke (method, NULL, NULL, NULL));
4831 /* note: result may be null if the flow is suppressed */
4835 MONO_OBJECT_SETREF (res, object_data, object_data);
4836 MONO_OBJECT_SETREF (res, async_state, state);
4838 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
4840 res->sync_completed = FALSE;
4841 res->completed = FALSE;
4847 mono_message_init (MonoDomain *domain,
4848 MonoMethodMessage *this,
4849 MonoReflectionMethod *method,
4850 MonoArray *out_args)
4852 static MonoClass *object_array_klass;
4853 static MonoClass *byte_array_klass;
4854 static MonoClass *string_array_klass;
4855 MonoMethodSignature *sig = mono_method_signature (method->method);
4861 if (!object_array_klass) {
4864 klass = mono_array_class_get (mono_defaults.object_class, 1);
4867 mono_memory_barrier ();
4868 object_array_klass = klass;
4870 klass = mono_array_class_get (mono_defaults.byte_class, 1);
4873 mono_memory_barrier ();
4874 byte_array_klass = klass;
4876 klass = mono_array_class_get (mono_defaults.string_class, 1);
4879 mono_memory_barrier ();
4880 string_array_klass = klass;
4883 MONO_OBJECT_SETREF (this, method, method);
4885 MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
4886 MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
4887 this->async_result = NULL;
4888 this->call_type = CallType_Sync;
4890 names = g_new (char *, sig->param_count);
4891 mono_method_get_param_names (method->method, (const char **) names);
4892 MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
4894 for (i = 0; i < sig->param_count; i++) {
4895 name = mono_string_new (domain, names [i]);
4896 mono_array_setref (this->names, i, name);
4900 for (i = 0, j = 0; i < sig->param_count; i++) {
4901 if (sig->params [i]->byref) {
4903 MonoObject* arg = mono_array_get (out_args, gpointer, j);
4904 mono_array_setref (this->args, i, arg);
4908 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
4912 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
4915 mono_array_set (this->arg_types, guint8, i, arg_type);
4920 * mono_remoting_invoke:
4921 * @real_proxy: pointer to a RealProxy object
4922 * @msg: The MonoMethodMessage to execute
4923 * @exc: used to store exceptions
4924 * @out_args: used to store output arguments
4926 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
4927 * IMessage interface and it is not trivial to extract results from there. So
4928 * we call an helper method PrivateInvoke instead of calling
4929 * RealProxy::Invoke() directly.
4931 * Returns: the result object.
4934 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
4935 MonoObject **exc, MonoArray **out_args)
4937 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
4940 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
4943 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
4945 real_proxy->vtable->domain->private_invoke_method = im;
4948 pa [0] = real_proxy;
4953 return mono_runtime_invoke (im, NULL, pa, exc);
4957 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
4958 MonoObject **exc, MonoArray **out_args)
4960 static MonoClass *object_array_klass;
4963 MonoMethodSignature *sig;
4965 int i, j, outarg_count = 0;
4967 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
4969 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
4970 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
4971 target = tp->rp->unwrapped_server;
4973 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
4977 domain = mono_domain_get ();
4978 method = msg->method->method;
4979 sig = mono_method_signature (method);
4981 for (i = 0; i < sig->param_count; i++) {
4982 if (sig->params [i]->byref)
4986 if (!object_array_klass) {
4989 klass = mono_array_class_get (mono_defaults.object_class, 1);
4992 mono_memory_barrier ();
4993 object_array_klass = klass;
4996 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
4997 *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
5000 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
5002 for (i = 0, j = 0; i < sig->param_count; i++) {
5003 if (sig->params [i]->byref) {
5005 arg = mono_array_get (msg->args, gpointer, i);
5006 mono_array_setref (*out_args, j, arg);
5015 * mono_print_unhandled_exception:
5016 * @exc: The exception
5018 * Prints the unhandled exception.
5021 mono_print_unhandled_exception (MonoObject *exc)
5023 char *message = (char *) "";
5027 gboolean free_message = FALSE;
5029 if (mono_object_isinst (exc, mono_defaults.exception_class)) {
5030 klass = exc->vtable->klass;
5032 while (klass && method == NULL) {
5033 method = mono_class_get_method_from_name_flags (klass, "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
5035 klass = klass->parent;
5040 str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL);
5042 message = mono_string_to_utf8 (str);
5043 free_message = TRUE;
5048 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
5049 * exc->vtable->klass->name, message);
5051 g_printerr ("\nUnhandled Exception: %s\n", message);
5058 * mono_delegate_ctor:
5059 * @this: pointer to an uninitialized delegate object
5060 * @target: target object
5061 * @addr: pointer to native code
5064 * Initialize a delegate and sets a specific method, not the one
5065 * associated with addr. This is useful when sharing generic code.
5066 * In that case addr will most probably not be associated with the
5067 * correct instantiation of the method.
5070 mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer addr, MonoMethod *method)
5072 MonoDelegate *delegate = (MonoDelegate *)this;
5079 delegate->method = method;
5081 class = this->vtable->klass;
5082 mono_stats.delegate_creations++;
5084 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5086 method = mono_marshal_get_remoting_invoke (method);
5087 delegate->method_ptr = mono_compile_method (method);
5088 MONO_OBJECT_SETREF (delegate, target, target);
5089 } else if (mono_method_signature (method)->hasthis && method->klass->valuetype) {
5090 method = mono_marshal_get_unbox_wrapper (method);
5091 delegate->method_ptr = mono_compile_method (method);
5092 MONO_OBJECT_SETREF (delegate, target, target);
5094 delegate->method_ptr = addr;
5095 MONO_OBJECT_SETREF (delegate, target, target);
5098 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->klass);
5102 * mono_delegate_ctor:
5103 * @this: pointer to an uninitialized delegate object
5104 * @target: target object
5105 * @addr: pointer to native code
5107 * This is used to initialize a delegate.
5110 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
5112 MonoDomain *domain = mono_domain_get ();
5114 MonoMethod *method = NULL;
5118 if ((ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr)))) {
5119 method = ji->method;
5120 g_assert (!method->klass->generic_container);
5123 mono_delegate_ctor_with_method (this, target, addr, method);
5127 * mono_method_call_message_new:
5128 * @method: method to encapsulate
5129 * @params: parameters to the method
5130 * @invoke: optional, delegate invoke.
5131 * @cb: async callback delegate.
5132 * @state: state passed to the async callback.
5134 * Translates arguments pointers into a MonoMethodMessage.
5137 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
5138 MonoDelegate **cb, MonoObject **state)
5140 MonoDomain *domain = mono_domain_get ();
5141 MonoMethodSignature *sig = mono_method_signature (method);
5142 MonoMethodMessage *msg;
5145 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5148 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
5149 count = sig->param_count - 2;
5151 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
5152 count = sig->param_count;
5155 for (i = 0; i < count; i++) {
5160 if (sig->params [i]->byref)
5161 vpos = *((gpointer *)params [i]);
5165 type = sig->params [i]->type;
5166 class = mono_class_from_mono_type (sig->params [i]);
5168 if (class->valuetype)
5169 arg = mono_value_box (domain, class, vpos);
5171 arg = *((MonoObject **)vpos);
5173 mono_array_setref (msg->args, i, arg);
5176 if (cb != NULL && state != NULL) {
5177 *cb = *((MonoDelegate **)params [i]);
5179 *state = *((MonoObject **)params [i]);
5186 * mono_method_return_message_restore:
5188 * Restore results from message based processing back to arguments pointers
5191 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
5193 MonoMethodSignature *sig = mono_method_signature (method);
5194 int i, j, type, size, out_len;
5196 if (out_args == NULL)
5198 out_len = mono_array_length (out_args);
5202 for (i = 0, j = 0; i < sig->param_count; i++) {
5203 MonoType *pt = sig->params [i];
5208 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
5210 arg = mono_array_get (out_args, gpointer, j);
5214 case MONO_TYPE_VOID:
5215 g_assert_not_reached ();
5219 case MONO_TYPE_BOOLEAN:
5222 case MONO_TYPE_CHAR:
5229 case MONO_TYPE_VALUETYPE: {
5231 size = mono_class_value_size (((MonoObject*)arg)->vtable->klass, NULL);
5232 memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
5235 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
5236 memset (*((gpointer *)params [i]), 0, size);
5240 case MONO_TYPE_STRING:
5241 case MONO_TYPE_CLASS:
5242 case MONO_TYPE_ARRAY:
5243 case MONO_TYPE_SZARRAY:
5244 case MONO_TYPE_OBJECT:
5245 **((MonoObject ***)params [i]) = (MonoObject *)arg;
5248 g_assert_not_reached ();
5257 * mono_load_remote_field:
5258 * @this: pointer to an object
5259 * @klass: klass of the object containing @field
5260 * @field: the field to load
5261 * @res: a storage to store the result
5263 * This method is called by the runtime on attempts to load fields of
5264 * transparent proxy objects. @this points to such TP, @klass is the class of
5265 * the object containing @field. @res is a storage location which can be
5266 * used to store the result.
5268 * Returns: an address pointing to the value of field.
5271 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
5273 static MonoMethod *getter = NULL;
5274 MonoDomain *domain = mono_domain_get ();
5275 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5276 MonoClass *field_class;
5277 MonoMethodMessage *msg;
5278 MonoArray *out_args;
5282 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5283 g_assert (res != NULL);
5285 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5286 mono_field_get_value (tp->rp->unwrapped_server, field, res);
5291 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
5295 field_class = mono_class_from_mono_type (field->type);
5297 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5298 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
5299 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
5301 full_name = mono_type_get_full_name (klass);
5302 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5303 mono_array_setref (msg->args, 1, mono_string_new (domain, field->name));
5306 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5308 if (exc) mono_raise_exception ((MonoException *)exc);
5310 if (mono_array_length (out_args) == 0)
5313 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
5315 if (field_class->valuetype) {
5316 return ((char *)*res) + sizeof (MonoObject);
5322 * mono_load_remote_field_new:
5327 * Missing documentation.
5330 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
5332 static MonoMethod *getter = NULL;
5333 MonoDomain *domain = mono_domain_get ();
5334 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5335 MonoClass *field_class;
5336 MonoMethodMessage *msg;
5337 MonoArray *out_args;
5338 MonoObject *exc, *res;
5341 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5343 field_class = mono_class_from_mono_type (field->type);
5345 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5347 if (field_class->valuetype) {
5348 res = mono_object_new (domain, field_class);
5349 val = ((gchar *) res) + sizeof (MonoObject);
5353 mono_field_get_value (tp->rp->unwrapped_server, field, val);
5358 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
5362 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5363 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
5365 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
5367 full_name = mono_type_get_full_name (klass);
5368 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5369 mono_array_setref (msg->args, 1, mono_string_new (domain, field->name));
5372 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5374 if (exc) mono_raise_exception ((MonoException *)exc);
5376 if (mono_array_length (out_args) == 0)
5379 res = mono_array_get (out_args, MonoObject *, 0);
5385 * mono_store_remote_field:
5386 * @this: pointer to an object
5387 * @klass: klass of the object containing @field
5388 * @field: the field to load
5389 * @val: the value/object to store
5391 * This method is called by the runtime on attempts to store fields of
5392 * transparent proxy objects. @this points to such TP, @klass is the class of
5393 * the object containing @field. @val is the new value to store in @field.
5396 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
5398 static MonoMethod *setter = NULL;
5399 MonoDomain *domain = mono_domain_get ();
5400 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5401 MonoClass *field_class;
5402 MonoMethodMessage *msg;
5403 MonoArray *out_args;
5408 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5410 field_class = mono_class_from_mono_type (field->type);
5412 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5413 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
5414 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
5419 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
5423 if (field_class->valuetype)
5424 arg = mono_value_box (domain, field_class, val);
5426 arg = *((MonoObject **)val);
5429 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5430 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
5432 full_name = mono_type_get_full_name (klass);
5433 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5434 mono_array_setref (msg->args, 1, mono_string_new (domain, field->name));
5435 mono_array_setref (msg->args, 2, arg);
5438 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5440 if (exc) mono_raise_exception ((MonoException *)exc);
5444 * mono_store_remote_field_new:
5450 * Missing documentation
5453 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
5455 static MonoMethod *setter = NULL;
5456 MonoDomain *domain = mono_domain_get ();
5457 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5458 MonoClass *field_class;
5459 MonoMethodMessage *msg;
5460 MonoArray *out_args;
5464 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5466 field_class = mono_class_from_mono_type (field->type);
5468 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5469 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
5470 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
5475 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
5479 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5480 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
5482 full_name = mono_type_get_full_name (klass);
5483 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5484 mono_array_setref (msg->args, 1, mono_string_new (domain, field->name));
5485 mono_array_setref (msg->args, 2, arg);
5488 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5490 if (exc) mono_raise_exception ((MonoException *)exc);
5494 * mono_create_ftnptr:
5496 * Given a function address, create a function descriptor for it.
5497 * This is only needed on IA64 and PPC64.
5500 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
5505 mono_domain_lock (domain);
5506 desc = mono_code_manager_reserve (domain->code_mp, 2 * sizeof (gpointer));
5507 mono_domain_unlock (domain);
5513 #elif defined(__ppc64__) || defined(__powerpc64__)
5516 mono_domain_lock (domain);
5517 desc = mono_code_manager_reserve (domain->code_mp, 3 * sizeof (gpointer));
5518 mono_domain_unlock (domain);
5531 * mono_get_addr_from_ftnptr:
5533 * Given a pointer to a function descriptor, return the function address.
5534 * This is only needed on IA64 and PPC64.
5537 mono_get_addr_from_ftnptr (gpointer descr)
5539 #if defined(__ia64__) || defined(__ppc64__) || defined(__powerpc64__)
5540 return *(gpointer*)descr;
5548 * mono_string_chars:
5551 * Returns a pointer to the UCS16 characters stored in the MonoString
5554 mono_string_chars(MonoString *s)
5556 /* This method is here only for documentation extraction, this is a macro */
5560 * mono_string_length:
5563 * Returns the lenght in characters of the string
5566 mono_string_length (MonoString *s)
5568 /* This method is here only for documentation extraction, this is a macro */