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/os/gc_wrapper.h>
37 #include <mono/utils/strenc.h>
40 #define NEED_TO_ZERO_PTRFREE 1
41 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = GC_MALLOC_ATOMIC ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
42 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = GC_MALLOC ((size)); (obj)->vtable = (vt);} while (0)
43 #ifdef HAVE_GC_GCJ_MALLOC
44 #define CREATION_SPEEDUP 1
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)
47 #define MAKE_STRING_DESCRIPTOR(bitmap,sz) GC_make_descriptor((GC_bitmap)(bitmap),(sz))
48 #define MAKE_DESCRIPTOR(bitmap,sz,objsize) GC_make_descriptor((GC_bitmap)(bitmap),(sz))
50 #define GC_NO_DESCRIPTOR (NULL)
51 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_MALLOC ((size)); *(gpointer*)dest = (type);} while (0)
52 #define MAKE_STRING_DESCRIPTOR(bitmap,sz) NULL
53 #define MAKE_DESCRIPTOR(bitmap,sz,objsize) NULL
57 #define GC_NO_DESCRIPTOR (NULL)
58 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
59 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
60 #define ALLOC_TYPED(dest,size,type) do { (dest) = mono_gc_alloc_obj (type, size);} while (0)
61 #define MAKE_STRING_DESCRIPTOR(bitmap,sz) mono_gc_make_descr_for_string ()
62 #define MAKE_DESCRIPTOR(bitmap,sz,objsize) mono_gc_make_descr_for_object ((bitmap), (sz), (objsize))
64 #define NEED_TO_ZERO_PTRFREE 1
65 #define GC_NO_DESCRIPTOR (NULL)
66 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = malloc ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
67 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = calloc (1, (size)); (obj)->vtable = (vt);} while (0)
68 #define ALLOC_TYPED(dest,size,type) do { (dest) = calloc (1, (size)); *(gpointer*)dest = (type);} while (0)
69 #define MAKE_STRING_DESCRIPTOR(bitmap,sz) NULL
70 #define MAKE_DESCRIPTOR(bitmap,sz,objsize) NULL
74 static MonoObject* mono_object_new_ptrfree (MonoVTable *vtable);
75 static MonoObject* mono_object_new_ptrfree_box (MonoVTable *vtable);
78 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value);
81 mono_ldstr_metdata_sig (MonoDomain *domain, const char* sig);
83 #define ldstr_lock() EnterCriticalSection (&ldstr_section)
84 #define ldstr_unlock() LeaveCriticalSection (&ldstr_section)
85 static CRITICAL_SECTION ldstr_section;
88 mono_runtime_object_init (MonoObject *this)
90 MonoMethod *method = NULL;
91 MonoClass *klass = this->vtable->klass;
93 method = mono_class_get_method_from_name (klass, ".ctor", 0);
96 if (method->klass->valuetype)
97 this = mono_object_unbox (this);
98 mono_runtime_invoke (method, this, NULL, NULL);
101 /* The pseudo algorithm for type initialization from the spec
102 Note it doesn't say anything about domains - only threads.
104 2. If the type is initialized you are done.
105 2.1. If the type is not yet initialized, try to take an
107 2.2. If successful, record this thread as responsible for
108 initializing the type and proceed to step 2.3.
109 2.2.1. If not, see whether this thread or any thread
110 waiting for this thread to complete already holds the lock.
111 2.2.2. If so, return since blocking would create a deadlock. This thread
112 will now see an incompletely initialized state for the type,
113 but no deadlock will arise.
114 2.2.3 If not, block until the type is initialized then return.
115 2.3 Initialize the parent type and then all interfaces implemented
117 2.4 Execute the type initialization code for this type.
118 2.5 Mark the type as initialized, release the initialization lock,
119 awaken any threads waiting for this type to be initialized,
126 guint32 initializing_tid;
127 guint32 waiting_count;
129 CRITICAL_SECTION initialization_section;
130 } TypeInitializationLock;
132 /* for locking access to type_initialization_hash and blocked_thread_hash */
133 #define mono_type_initialization_lock() EnterCriticalSection (&type_initialization_section)
134 #define mono_type_initialization_unlock() LeaveCriticalSection (&type_initialization_section)
135 static CRITICAL_SECTION type_initialization_section;
137 /* from vtable to lock */
138 static GHashTable *type_initialization_hash;
140 /* from thread id to thread id being waited on */
141 static GHashTable *blocked_thread_hash;
144 static MonoThread *main_thread;
147 * mono_thread_set_main:
148 * @thread: thread to set as the main thread
150 * This function can be used to instruct the runtime to treat @thread
151 * as the main thread, ie, the thread that would normally execute the Main()
152 * method. This basically means that at the end of @thread, the runtime will
153 * wait for the existing foreground threads to quit and other such details.
156 mono_thread_set_main (MonoThread *thread)
158 main_thread = thread;
162 mono_thread_get_main (void)
168 mono_type_initialization_init (void)
170 InitializeCriticalSection (&type_initialization_section);
171 type_initialization_hash = g_hash_table_new (NULL, NULL);
172 blocked_thread_hash = g_hash_table_new (NULL, NULL);
173 InitializeCriticalSection (&ldstr_section);
177 mono_type_initialization_cleanup (void)
180 /* This is causing race conditions with
181 * mono_release_type_locks
183 DeleteCriticalSection (&type_initialization_section);
185 DeleteCriticalSection (&ldstr_section);
189 * get_type_init_exception_for_vtable:
191 * Return the stored type initialization exception for VTABLE.
193 static MonoException*
194 get_type_init_exception_for_vtable (MonoVTable *vtable)
196 MonoDomain *domain = vtable->domain;
197 MonoClass *klass = vtable->klass;
201 g_assert (vtable->init_failed);
204 * If the initializing thread was rudely aborted, the exception is not stored
208 mono_domain_lock (domain);
209 if (domain->type_init_exception_hash)
210 ex = mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
211 mono_domain_unlock (domain);
214 if (klass->name_space && *klass->name_space)
215 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
217 full_name = g_strdup (klass->name);
218 ex = mono_get_exception_type_initialization (full_name, NULL);
226 * mono_runtime_class_init:
227 * @vtable: vtable that needs to be initialized
229 * This routine calls the class constructor for @vtable.
232 mono_runtime_class_init (MonoVTable *vtable)
235 MonoException *exc_to_throw;
236 MonoMethod *method = NULL;
242 if (vtable->initialized)
246 klass = vtable->klass;
248 if (!klass->image->checked_module_cctor) {
249 mono_image_check_for_module_cctor (klass->image);
250 if (klass->image->has_module_cctor) {
251 MonoClass *module_klass = mono_class_get (klass->image, MONO_TOKEN_TYPE_DEF | 1);
252 mono_runtime_class_init (mono_class_vtable (vtable->domain, module_klass));
255 method = mono_class_get_cctor (klass);
258 MonoDomain *domain = vtable->domain;
259 TypeInitializationLock *lock;
260 guint32 tid = GetCurrentThreadId();
261 int do_initialization = 0;
262 MonoDomain *last_domain = NULL;
264 mono_type_initialization_lock ();
265 /* double check... */
266 if (vtable->initialized) {
267 mono_type_initialization_unlock ();
270 if (vtable->init_failed) {
271 mono_type_initialization_unlock ();
273 /* The type initialization already failed once, rethrow the same exception */
274 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
277 lock = g_hash_table_lookup (type_initialization_hash, vtable);
279 /* This thread will get to do the initialization */
280 if (mono_domain_get () != domain) {
281 /* Transfer into the target domain */
282 last_domain = mono_domain_get ();
283 if (!mono_domain_set (domain, FALSE)) {
284 vtable->initialized = 1;
285 mono_type_initialization_unlock ();
286 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
289 lock = g_malloc (sizeof(TypeInitializationLock));
290 InitializeCriticalSection (&lock->initialization_section);
291 lock->initializing_tid = tid;
292 lock->waiting_count = 1;
294 /* grab the vtable lock while this thread still owns type_initialization_section */
295 EnterCriticalSection (&lock->initialization_section);
296 g_hash_table_insert (type_initialization_hash, vtable, lock);
297 do_initialization = 1;
300 TypeInitializationLock *pending_lock;
302 if (lock->initializing_tid == tid || lock->done) {
303 mono_type_initialization_unlock ();
306 /* see if the thread doing the initialization is already blocked on this thread */
307 blocked = GUINT_TO_POINTER (lock->initializing_tid);
308 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
309 if (pending_lock->initializing_tid == tid) {
310 if (!pending_lock->done) {
311 mono_type_initialization_unlock ();
314 /* the thread doing the initialization is blocked on this thread,
315 but on a lock that has already been freed. It just hasn't got
320 blocked = GUINT_TO_POINTER (pending_lock->initializing_tid);
322 ++lock->waiting_count;
323 /* record the fact that we are waiting on the initializing thread */
324 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
326 mono_type_initialization_unlock ();
328 if (do_initialization) {
329 mono_runtime_invoke (method, NULL, NULL, (MonoObject **) &exc);
331 /* If the initialization failed, mark the class as unusable. */
332 /* Avoid infinite loops */
334 (klass->image == mono_defaults.corlib &&
335 !strcmp (klass->name_space, "System") &&
336 !strcmp (klass->name, "TypeInitializationException")))) {
337 vtable->init_failed = 1;
339 if (klass->name_space && *klass->name_space)
340 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
342 full_name = g_strdup (klass->name);
343 exc_to_throw = mono_get_exception_type_initialization (full_name, exc);
347 * Store the exception object so it could be thrown on subsequent
350 mono_domain_lock (domain);
351 if (!domain->type_init_exception_hash)
352 domain->type_init_exception_hash = mono_g_hash_table_new_type (mono_aligned_addr_hash, NULL, MONO_HASH_VALUE_GC);
353 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
354 mono_domain_unlock (domain);
358 mono_domain_set (last_domain, TRUE);
360 LeaveCriticalSection (&lock->initialization_section);
362 /* this just blocks until the initializing thread is done */
363 EnterCriticalSection (&lock->initialization_section);
364 LeaveCriticalSection (&lock->initialization_section);
367 mono_type_initialization_lock ();
368 if (lock->initializing_tid != tid)
369 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
370 --lock->waiting_count;
371 if (lock->waiting_count == 0) {
372 DeleteCriticalSection (&lock->initialization_section);
373 g_hash_table_remove (type_initialization_hash, vtable);
376 if (!vtable->init_failed)
377 vtable->initialized = 1;
378 mono_type_initialization_unlock ();
380 if (vtable->init_failed) {
381 /* Either we were the initializing thread or we waited for the initialization */
382 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
385 vtable->initialized = 1;
391 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
393 MonoVTable *vtable = (MonoVTable*)key;
395 TypeInitializationLock *lock = (TypeInitializationLock*) value;
396 if (lock->initializing_tid == GPOINTER_TO_UINT (user) && !lock->done) {
399 * Have to set this since it cannot be set by the normal code in
400 * mono_runtime_class_init (). In this case, the exception object is not stored,
401 * and get_type_init_exception_for_class () needs to be aware of this.
403 vtable->init_failed = 1;
404 LeaveCriticalSection (&lock->initialization_section);
405 --lock->waiting_count;
406 if (lock->waiting_count == 0) {
407 DeleteCriticalSection (&lock->initialization_section);
416 mono_release_type_locks (MonoThread *thread)
418 mono_type_initialization_lock ();
419 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, (gpointer)(gsize)(thread->tid));
420 mono_type_initialization_unlock ();
424 default_trampoline (MonoMethod *method)
430 default_remoting_trampoline (MonoMethod *method, MonoRemotingTarget target)
432 g_error ("remoting not installed");
437 default_delegate_trampoline (MonoClass *klass)
439 g_assert_not_reached ();
443 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
444 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
445 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
446 static MonoImtThunkBuilder imt_thunk_builder = NULL;
447 #define ARCH_USE_IMT (imt_thunk_builder != NULL)
448 #if (MONO_IMT_SIZE > 32)
449 #error "MONO_IMT_SIZE cannot be larger than 32"
453 mono_install_trampoline (MonoTrampoline func)
455 arch_create_jit_trampoline = func? func: default_trampoline;
459 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
461 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
465 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
467 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
471 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
472 imt_thunk_builder = func;
475 static MonoCompileFunc default_mono_compile_method = NULL;
478 * mono_install_compile_method:
479 * @func: function to install
481 * This is a VM internal routine
484 mono_install_compile_method (MonoCompileFunc func)
486 default_mono_compile_method = func;
490 * mono_compile_method:
491 * @method: The method to compile.
493 * This JIT-compiles the method, and returns the pointer to the native code
497 mono_compile_method (MonoMethod *method)
499 if (!default_mono_compile_method) {
500 g_error ("compile method called on uninitialized runtime");
503 return default_mono_compile_method (method);
506 static MonoFreeMethodFunc default_mono_free_method = NULL;
509 * mono_install_free_method:
510 * @func: pointer to the MonoFreeMethodFunc used to release a method
512 * This is an internal VM routine, it is used for the engines to
513 * register a handler to release the resources associated with a method.
515 * Methods are freed when no more references to the delegate that holds
519 mono_install_free_method (MonoFreeMethodFunc func)
521 default_mono_free_method = func;
525 * mono_runtime_free_method:
526 * @domain; domain where the method is hosted
527 * @method: method to release
529 * This routine is invoked to free the resources associated with
530 * a method that has been JIT compiled. This is used to discard
531 * methods that were used only temporarily (for example, used in marshalling)
535 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
537 if (default_mono_free_method != NULL)
538 default_mono_free_method (domain, method);
540 mono_free_method (method);
543 static MonoInitVTableFunc init_vtable_func = NULL;
546 * mono_install_init_vtable:
547 * @func: pointer to the function to be installed
549 * Register a function which will be called by the runtime to initialize the
550 * method pointers inside a vtable. The JIT can use this function to load the
551 * vtable from the AOT file for example.
554 mono_install_init_vtable (MonoInitVTableFunc func)
556 init_vtable_func = func;
560 * The vtables in the root appdomain are assumed to be reachable by other
561 * roots, and we don't use typed allocation in the other domains.
564 /* The sync block is no longer a GC pointer */
565 #define GC_HEADER_BITMAP (0)
567 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
570 compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
572 MonoClassField *field;
578 max_size = mono_class_data_size (class) / sizeof (gpointer);
580 max_size = class->instance_size / sizeof (gpointer);
581 if (max_size >= size) {
582 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
585 for (p = class; p != NULL; p = p->parent) {
586 gpointer iter = NULL;
587 while ((field = mono_class_get_fields (p, &iter))) {
591 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
594 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
597 /* FIXME: should not happen, flag as type load error */
598 if (field->type->byref)
601 pos = field->offset / sizeof (gpointer);
604 type = mono_type_get_underlying_type (field->type);
605 switch (type->type) {
608 case MONO_TYPE_FNPTR:
610 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
615 if (class->image != mono_defaults.corlib)
618 case MONO_TYPE_STRING:
619 case MONO_TYPE_SZARRAY:
620 case MONO_TYPE_CLASS:
621 case MONO_TYPE_OBJECT:
622 case MONO_TYPE_ARRAY:
623 g_assert ((field->offset % sizeof(gpointer)) == 0);
625 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
626 *max_set = MAX (*max_set, pos);
628 case MONO_TYPE_GENERICINST:
629 if (!mono_type_generic_inst_is_valuetype (type)) {
630 g_assert ((field->offset % sizeof(gpointer)) == 0);
632 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
633 *max_set = MAX (*max_set, pos);
638 case MONO_TYPE_VALUETYPE: {
639 MonoClass *fclass = mono_class_from_mono_type (field->type);
640 if (fclass->has_references) {
641 /* remove the object header */
642 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
656 case MONO_TYPE_BOOLEAN:
660 g_assert_not_reached ();
672 * similar to the above, but sets the bits in the bitmap for any non-ref field
673 * and ignores static fields
676 compute_class_non_ref_bitmap (MonoClass *class, gsize *bitmap, int size, int offset)
678 MonoClassField *field;
683 max_size = class->instance_size / sizeof (gpointer);
684 if (max_size >= size) {
685 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
688 for (p = class; p != NULL; p = p->parent) {
689 gpointer iter = NULL;
690 while ((field = mono_class_get_fields (p, &iter))) {
693 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
695 /* FIXME: should not happen, flag as type load error */
696 if (field->type->byref)
699 pos = field->offset / sizeof (gpointer);
702 type = mono_type_get_underlying_type (field->type);
703 switch (type->type) {
704 #if SIZEOF_VOID_P == 8
708 case MONO_TYPE_FNPTR:
713 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
714 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
715 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
718 #if SIZEOF_VOID_P == 4
722 case MONO_TYPE_FNPTR:
727 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
728 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
729 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
735 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
736 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
737 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
740 case MONO_TYPE_BOOLEAN:
743 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
745 case MONO_TYPE_STRING:
746 case MONO_TYPE_SZARRAY:
747 case MONO_TYPE_CLASS:
748 case MONO_TYPE_OBJECT:
749 case MONO_TYPE_ARRAY:
751 case MONO_TYPE_GENERICINST:
752 if (!mono_type_generic_inst_is_valuetype (type)) {
757 case MONO_TYPE_VALUETYPE: {
758 MonoClass *fclass = mono_class_from_mono_type (field->type);
759 /* remove the object header */
760 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
764 g_assert_not_reached ();
773 * mono_class_insecure_overlapping:
774 * check if a class with explicit layout has references and non-references
775 * fields overlapping.
777 * Returns: TRUE if it is insecure to load the type.
780 mono_class_insecure_overlapping (MonoClass *klass)
784 gsize default_bitmap [4] = {0};
786 gsize default_nrbitmap [4] = {0};
787 int i, insecure = FALSE;
790 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
791 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
793 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
794 int idx = i % (sizeof (bitmap [0]) * 8);
795 if (bitmap [idx] & nrbitmap [idx]) {
800 if (bitmap != default_bitmap)
802 if (nrbitmap != default_nrbitmap)
805 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
813 mono_class_compute_gc_descriptor (MonoClass *class)
817 gsize default_bitmap [4] = {0};
818 static gboolean gcj_inited = FALSE;
823 mono_register_jit_icall (mono_object_new_ptrfree, "mono_object_new_ptrfree", mono_create_icall_signature ("object ptr"), FALSE);
824 mono_register_jit_icall (mono_object_new_ptrfree_box, "mono_object_new_ptrfree_box", mono_create_icall_signature ("object ptr"), FALSE);
825 mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
827 #ifdef HAVE_GC_GCJ_MALLOC
829 GC_init_gcj_malloc (5, NULL);
831 #ifdef GC_REDIRECT_TO_LOCAL
832 mono_register_jit_icall (GC_local_gcj_malloc, "GC_local_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
833 mono_register_jit_icall (GC_local_gcj_fast_malloc, "GC_local_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
835 mono_register_jit_icall (GC_gcj_malloc, "GC_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
836 mono_register_jit_icall (GC_gcj_fast_malloc, "GC_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
839 mono_loader_unlock ();
843 mono_class_init (class);
845 if (class->gc_descr_inited)
848 class->gc_descr_inited = TRUE;
849 class->gc_descr = GC_NO_DESCRIPTOR;
851 bitmap = default_bitmap;
852 if (class == mono_defaults.string_class) {
853 class->gc_descr = (gpointer)MAKE_STRING_DESCRIPTOR (bitmap, 2);
854 } else if (class->rank) {
855 mono_class_compute_gc_descriptor (class->element_class);
857 /* libgc has no usable support for arrays... */
858 if (!class->element_class->valuetype) {
860 class->gc_descr = mono_gc_make_descr_for_array (TRUE, &abm, 1, sizeof (gpointer));
861 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
862 class->name_space, class->name);*/
864 /* remove the object header */
865 bitmap = compute_class_bitmap (class->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
866 class->gc_descr = mono_gc_make_descr_for_array (TRUE, bitmap, mono_array_element_size (class) / sizeof (gpointer), mono_array_element_size (class));
867 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
868 class->name_space, class->name);*/
869 if (bitmap != default_bitmap)
874 /*static int count = 0;
877 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
879 /* It seems there are issues when the bitmap doesn't fit: play it safe */
881 /*g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);*/
882 if (bitmap != default_bitmap)
887 class->gc_descr = (gpointer)MAKE_DESCRIPTOR (bitmap, max_set + 1, class->instance_size);
888 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
889 if (bitmap != default_bitmap)
895 * field_is_special_static:
896 * @fklass: The MonoClass to look up.
897 * @field: The MonoClassField describing the field.
899 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
900 * SPECIAL_STATIC_NONE otherwise.
903 field_is_special_static (MonoClass *fklass, MonoClassField *field)
905 MonoCustomAttrInfo *ainfo;
907 ainfo = mono_custom_attrs_from_field (fklass, field);
910 for (i = 0; i < ainfo->num_attrs; ++i) {
911 MonoClass *klass = ainfo->attrs [i].ctor->klass;
912 if (klass->image == mono_defaults.corlib) {
913 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
914 mono_custom_attrs_free (ainfo);
915 return SPECIAL_STATIC_THREAD;
917 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
918 mono_custom_attrs_free (ainfo);
919 return SPECIAL_STATIC_CONTEXT;
923 mono_custom_attrs_free (ainfo);
924 return SPECIAL_STATIC_NONE;
927 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
928 #define mix(a,b,c) { \
929 a -= c; a ^= rot(c, 4); c += b; \
930 b -= a; b ^= rot(a, 6); a += c; \
931 c -= b; c ^= rot(b, 8); b += a; \
932 a -= c; a ^= rot(c,16); c += b; \
933 b -= a; b ^= rot(a,19); a += c; \
934 c -= b; c ^= rot(b, 4); b += a; \
936 #define final(a,b,c) { \
937 c ^= b; c -= rot(b,14); \
938 a ^= c; a -= rot(c,11); \
939 b ^= a; b -= rot(a,25); \
940 c ^= b; c -= rot(b,16); \
941 a ^= c; a -= rot(c,4); \
942 b ^= a; b -= rot(a,14); \
943 c ^= b; c -= rot(b,24); \
947 mono_method_get_imt_slot (MonoMethod *method) {
948 MonoMethodSignature *sig = mono_method_signature (method);
949 int hashes_count = sig->param_count + 4;
950 guint32 *hashes_start = malloc (hashes_count * sizeof (guint32));
951 guint32 *hashes = hashes_start;
955 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
956 printf ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod\n",
957 method->klass->name_space, method->klass->name, method->name);
958 g_assert_not_reached ();
961 /* Initialize hashes */
962 hashes [0] = g_str_hash (method->klass->name);
963 hashes [1] = g_str_hash (method->klass->name_space);
964 hashes [2] = g_str_hash (method->name);
965 hashes [3] = mono_metadata_type_hash (sig->ret);
966 for (i = 0; i < sig->param_count; i++) {
967 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
970 /* Setup internal state */
971 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
973 /* Handle most of the hashes */
974 while (hashes_count > 3) {
983 /* Handle the last 3 hashes (all the case statements fall through) */
984 switch (hashes_count) {
985 case 3 : c += hashes [2];
986 case 2 : b += hashes [1];
987 case 1 : a += hashes [0];
989 case 0: /* nothing left to add */
994 /* Report the result */
995 return c % MONO_IMT_SIZE;
1004 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot) {
1005 guint32 imt_slot = mono_method_get_imt_slot (method);
1006 MonoImtBuilderEntry *entry = malloc (sizeof (MonoImtBuilderEntry));
1008 entry->method = method;
1009 entry->vtable_slot = vtable_slot;
1010 entry->next = imt_builder [imt_slot];
1011 if (imt_builder [imt_slot] != NULL) {
1012 entry->children = imt_builder [imt_slot]->children + 1;
1013 if (entry->children == 1) {
1014 mono_stats.imt_slots_with_collisions++;
1015 *imt_collisions_bitmap |= (1 << imt_slot);
1018 entry->children = 0;
1019 mono_stats.imt_used_slots++;
1021 imt_builder [imt_slot] = entry;
1023 printf ("Added IMT slot for method %s.%s.%s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1024 method->klass->name_space, method->klass->name,
1025 method->name, imt_slot, vtable_slot, entry->children);
1031 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1033 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1037 e->method->klass->name_space,
1038 e->method->klass->name,
1041 printf (" * %s: NULL\n", message);
1047 compare_imt_builder_entries (const void *p1, const void *p2) {
1048 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1049 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1051 return (e1->method < e2->method) ? -1 : ((e1->method > e2->method) ? 1 : 0);
1055 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1057 int count = end - start;
1058 int chunk_start = out_array->len;
1061 for (i = start; i < end; ++i) {
1062 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1063 item->method = sorted_array [i]->method;
1064 item->vtable_slot = sorted_array [i]->vtable_slot;
1065 item->is_equals = TRUE;
1067 item->check_target_idx = out_array->len + 1;
1069 item->check_target_idx = 0;
1070 g_ptr_array_add (out_array, item);
1073 int middle = start + count / 2;
1074 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1076 item->method = sorted_array [middle]->method;
1077 item->is_equals = FALSE;
1078 g_ptr_array_add (out_array, item);
1079 imt_emit_ir (sorted_array, start, middle, out_array);
1080 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1086 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1087 int number_of_entries = entries->children + 1;
1088 MonoImtBuilderEntry **sorted_array = malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1089 GPtrArray *result = g_ptr_array_new ();
1090 MonoImtBuilderEntry *current_entry;
1093 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1094 sorted_array [i] = current_entry;
1096 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1098 /*for (i = 0; i < number_of_entries; i++) {
1099 print_imt_entry (" sorted array:", sorted_array [i], i);
1102 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1104 free (sorted_array);
1109 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry) {
1110 if (imt_builder_entry != NULL) {
1111 if (imt_builder_entry->children == 0) {
1112 /* No collision, return the vtable slot contents */
1113 return vtable->vtable [imt_builder_entry->vtable_slot];
1115 /* Collision, build the thunk */
1116 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1119 result = imt_thunk_builder (vtable, domain, (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len);
1120 for (i = 0; i < imt_ir->len; ++i)
1121 g_free (g_ptr_array_index (imt_ir, i));
1122 g_ptr_array_free (imt_ir, TRUE);
1132 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1135 guint32 imt_collisions_bitmap = 0;
1136 MonoImtBuilderEntry **imt_builder = calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1137 int method_count = 0;
1138 gboolean record_method_count_for_max_collisions = FALSE;
1141 printf ("Building IMT for class %s.%s\n", klass->name_space, klass->name);
1143 for (i = 0; i < klass->interface_offsets_count; ++i) {
1144 MonoClass *iface = klass->interfaces_packed [i];
1145 int interface_offset = klass->interface_offsets_packed [i];
1146 int method_slot_in_interface;
1147 mono_class_setup_methods (iface);
1148 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1149 MonoMethod *method = iface->methods [method_slot_in_interface];
1150 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface);
1153 if (extra_interfaces) {
1154 int interface_offset = klass->vtable_size;
1156 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1157 MonoClass* iface = list_item->data;
1158 int method_slot_in_interface;
1159 mono_class_setup_methods (iface);
1160 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1161 MonoMethod *method = iface->methods [method_slot_in_interface];
1162 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface);
1164 interface_offset += iface->method.count;
1167 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1168 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i]);
1170 printf ("initialize_imt_slot[%d]: %p\n", i, imt [i]);
1172 if (imt_builder [i] != NULL) {
1173 int methods_in_slot = imt_builder [i]->children + 1;
1174 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1175 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1176 record_method_count_for_max_collisions = TRUE;
1178 method_count += methods_in_slot;
1182 mono_stats.imt_number_of_methods += method_count;
1183 if (record_method_count_for_max_collisions) {
1184 mono_stats.imt_method_count_when_max_collisions = method_count;
1187 for (i = 0; i < MONO_IMT_SIZE; i++) {
1188 MonoImtBuilderEntry* entry = imt_builder [i];
1189 while (entry != NULL) {
1190 MonoImtBuilderEntry* next = entry->next;
1196 vt->imt_collisions_bitmap = imt_collisions_bitmap;
1199 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class);
1202 * mono_class_vtable:
1203 * @domain: the application domain
1204 * @class: the class to initialize
1206 * VTables are domain specific because we create domain specific code, and
1207 * they contain the domain specific static class data.
1210 mono_class_vtable (MonoDomain *domain, MonoClass *class)
1212 MonoClassRuntimeInfo *runtime_info;
1216 /* this check can be inlined in jitted code, too */
1217 runtime_info = class->runtime_info;
1218 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1219 return runtime_info->domain_vtables [domain->domain_id];
1220 return mono_class_create_runtime_vtable (domain, class);
1224 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class)
1227 MonoClassRuntimeInfo *runtime_info, *old_info;
1228 MonoClassField *field;
1231 int imt_table_bytes = 0;
1232 gboolean inited = FALSE;
1233 guint32 vtable_size, class_size;
1235 guint32 constant_cols [MONO_CONSTANT_SIZE];
1237 gpointer *interface_offsets;
1239 mono_domain_lock (domain);
1240 runtime_info = class->runtime_info;
1241 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1242 mono_domain_unlock (domain);
1243 return runtime_info->domain_vtables [domain->domain_id];
1245 if (!class->inited || class->exception_type) {
1246 if (!mono_class_init (class) || class->exception_type){
1248 mono_domain_unlock (domain);
1249 exc = mono_class_get_exception_for_failure (class);
1251 mono_raise_exception (exc);
1255 mono_class_init (class);
1257 /* FIXME: This should be done by mono_class_init () for dynamic classes as well */
1258 if (class->image->dynamic)
1259 mono_class_setup_vtable (class);
1262 vtable_size = sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
1263 if (class->interface_offsets_count) {
1264 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1265 vtable_size += sizeof (gpointer) * (MONO_IMT_SIZE);
1266 mono_stats.imt_number_of_tables++;
1267 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
1270 vtable_size = sizeof (gpointer) * (class->max_interface_id + 1) +
1271 sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
1274 mono_stats.used_class_count++;
1275 mono_stats.class_vtable_size += vtable_size;
1276 interface_offsets = mono_mempool_alloc0 (domain->mp, vtable_size);
1279 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1281 vt = (MonoVTable*) (interface_offsets + class->max_interface_id + 1);
1283 vt->rank = class->rank;
1284 vt->domain = domain;
1286 mono_class_compute_gc_descriptor (class);
1288 * We can't use typed allocation in the non-root domains, since the
1289 * collector needs the GC descriptor stored in the vtable even after
1290 * the mempool containing the vtable is destroyed when the domain is
1291 * unloaded. An alternative might be to allocate vtables in the GC
1292 * heap, but this does not seem to work (it leads to crashes inside
1293 * libgc). If that approach is tried, two gc descriptors need to be
1294 * allocated for each class: one for the root domain, and one for all
1295 * other domains. The second descriptor should contain a bit for the
1296 * vtable field in MonoObject, since we can no longer assume the
1297 * vtable is reachable by other roots after the appdomain is unloaded.
1299 #ifdef HAVE_BOEHM_GC
1300 if (domain != mono_get_root_domain ())
1301 vt->gc_descr = GC_NO_DESCRIPTOR;
1304 vt->gc_descr = class->gc_descr;
1306 if ((class_size = mono_class_data_size (class))) {
1307 if (class->has_static_refs) {
1308 gpointer statics_gc_descr;
1310 gsize default_bitmap [4] = {0};
1313 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1314 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
1315 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set? max_set + 1: 0);
1316 vt->data = mono_gc_alloc_fixed (class_size, statics_gc_descr);
1317 mono_domain_add_class_static_data (domain, class, vt->data, NULL);
1318 if (bitmap != default_bitmap)
1321 vt->data = mono_mempool_alloc0 (domain->mp, class_size);
1323 mono_stats.class_static_data_size += class_size;
1328 while ((field = mono_class_get_fields (class, &iter))) {
1329 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1331 if (mono_field_is_deleted (field))
1333 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1334 gint32 special_static = class->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (class, field);
1335 if (special_static != SPECIAL_STATIC_NONE) {
1336 guint32 size, offset;
1338 size = mono_type_size (field->type, &align);
1339 offset = mono_alloc_special_static_data (special_static, size, align);
1340 if (!domain->special_static_fields)
1341 domain->special_static_fields = g_hash_table_new (NULL, NULL);
1342 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
1346 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
1347 MonoClass *fklass = mono_class_from_mono_type (field->type);
1348 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
1349 t = (char*)vt->data + field->offset;
1350 if (fklass->valuetype) {
1351 memcpy (t, field->data, mono_class_value_size (fklass, NULL));
1353 /* it's a pointer type: add check */
1354 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
1355 *t = *(char *)field->data;
1359 if (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT))
1362 /* later do this only on demand if needed */
1364 cindex = mono_metadata_get_constant_index (class->image, mono_class_get_field_token (field), cindex + 1);
1366 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA));
1368 mono_metadata_decode_row (&class->image->tables [MONO_TABLE_CONSTANT], cindex - 1, constant_cols, MONO_CONSTANT_SIZE);
1369 field->def_type = constant_cols [MONO_CONSTANT_TYPE];
1370 field->data = (gpointer)mono_metadata_blob_heap (class->image, constant_cols [MONO_CONSTANT_VALUE]);
1375 vt->max_interface_id = class->max_interface_id;
1376 vt->interface_bitmap = class->interface_bitmap;
1378 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
1379 // class->name, class->interface_offsets_count);
1381 if (! ARCH_USE_IMT) {
1382 /* initialize interface offsets */
1383 for (i = 0; i < class->interface_offsets_count; ++i) {
1384 int interface_id = class->interfaces_packed [i]->interface_id;
1385 int slot = class->interface_offsets_packed [i];
1386 interface_offsets [class->max_interface_id - interface_id] = &(vt->vtable [slot]);
1391 * arch_create_jit_trampoline () can recursively call this function again
1392 * because it compiles icall methods right away.
1394 /* FIXME: class_vtable_hash is basically obsolete now: remove as soon
1395 * as we change the code in appdomain.c to invalidate vtables by
1396 * looking at the possible MonoClasses created for the domain.
1398 g_hash_table_insert (domain->class_vtable_hash, class, vt);
1399 /* class->runtime_info is protected by the loader lock, both when
1400 * it it enlarged and when it is stored info.
1402 mono_loader_lock ();
1403 old_info = class->runtime_info;
1404 if (old_info && old_info->max_domain >= domain->domain_id) {
1405 /* someone already created a large enough runtime info */
1406 old_info->domain_vtables [domain->domain_id] = vt;
1408 int new_size = domain->domain_id;
1410 new_size = MAX (new_size, old_info->max_domain);
1412 /* make the new size a power of two */
1414 while (new_size > i)
1417 /* this is a bounded memory retention issue: may want to
1418 * handle it differently when we'll have a rcu-like system.
1420 runtime_info = mono_mempool_alloc0 (class->image->mempool, sizeof (MonoClassRuntimeInfo) + new_size * sizeof (gpointer));
1421 runtime_info->max_domain = new_size - 1;
1422 /* copy the stuff from the older info */
1424 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
1426 runtime_info->domain_vtables [domain->domain_id] = vt;
1427 /* keep this last (add membarrier) */
1428 class->runtime_info = runtime_info;
1430 mono_loader_unlock ();
1432 /* initialize vtable */
1433 if (init_vtable_func)
1434 inited = init_vtable_func (vt);
1437 mono_class_setup_vtable (class);
1439 for (i = 0; i < class->vtable_size; ++i) {
1442 if ((cm = class->vtable [i])) {
1443 if (mono_method_signature (cm)->generic_param_count)
1444 vt->vtable [i] = cm;
1446 vt->vtable [i] = arch_create_jit_trampoline (cm);
1451 if (ARCH_USE_IMT && imt_table_bytes) {
1452 /* Now that the vtable is full, we can actually fill up the IMT */
1453 build_imt (class, vt, domain, interface_offsets, NULL);
1456 mono_domain_unlock (domain);
1458 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
1459 if (mono_is_security_manager_active () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND)) {
1460 MonoException *exc = mono_class_get_exception_for_failure (class);
1462 mono_raise_exception (exc);
1465 /* make sure the the parent is initialized */
1467 mono_class_vtable (domain, class->parent);
1469 vt->type = mono_type_get_object (domain, &class->byval_arg);
1470 if (class->contextbound)
1479 * mono_class_proxy_vtable:
1480 * @domain: the application domain
1481 * @remove_class: the remote class
1483 * Creates a vtable for transparent proxies. It is basically
1484 * a copy of the real vtable of the class wrapped in @remote_class,
1485 * but all function pointers invoke the remoting functions, and
1486 * vtable->klass points to the transparent proxy class, and not to @class.
1489 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
1491 MonoVTable *vt, *pvt;
1492 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
1494 GSList *extra_interfaces = NULL;
1495 MonoClass *class = remote_class->proxy_class;
1496 gpointer *interface_offsets;
1498 vt = mono_class_vtable (domain, class);
1499 max_interface_id = vt->max_interface_id;
1501 /* Calculate vtable space for extra interfaces */
1502 for (j = 0; j < remote_class->interface_count; j++) {
1503 MonoClass* iclass = remote_class->interfaces[j];
1507 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
1508 continue; /* interface implemented by the class */
1509 if (g_slist_find (extra_interfaces, iclass))
1512 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
1514 method_count = mono_class_num_methods (iclass);
1516 ifaces = mono_class_get_implemented_interfaces (iclass);
1518 for (i = 0; i < ifaces->len; ++i) {
1519 MonoClass *ic = g_ptr_array_index (ifaces, i);
1520 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
1521 continue; /* interface implemented by the class */
1522 if (g_slist_find (extra_interfaces, ic))
1524 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
1525 method_count += mono_class_num_methods (ic);
1527 g_ptr_array_free (ifaces, TRUE);
1530 extra_interface_vtsize += method_count * sizeof (gpointer);
1531 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
1535 mono_stats.imt_number_of_tables++;
1536 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
1537 vtsize = sizeof (gpointer) * (MONO_IMT_SIZE) +
1538 sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
1540 vtsize = sizeof (gpointer) * (class->max_interface_id + 1) +
1541 sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
1544 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
1546 interface_offsets = mono_mempool_alloc0 (domain->mp, vtsize + extra_interface_vtsize);
1548 pvt = (MonoVTable*) (interface_offsets + MONO_IMT_SIZE);
1550 pvt = (MonoVTable*) (interface_offsets + max_interface_id + 1);
1551 memcpy (pvt, vt, sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer));
1553 pvt->klass = mono_defaults.transparent_proxy_class;
1554 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
1555 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
1557 /* initialize vtable */
1558 mono_class_setup_vtable (class);
1559 for (i = 0; i < class->vtable_size; ++i) {
1562 if ((cm = class->vtable [i]))
1563 pvt->vtable [i] = arch_create_remoting_trampoline (cm, target_type);
1566 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
1567 /* create trampolines for abstract methods */
1568 for (k = class; k; k = k->parent) {
1570 gpointer iter = NULL;
1571 while ((m = mono_class_get_methods (k, &iter)))
1572 if (!pvt->vtable [m->slot])
1573 pvt->vtable [m->slot] = arch_create_remoting_trampoline (m, target_type);
1577 pvt->max_interface_id = max_interface_id;
1578 pvt->interface_bitmap = mono_mempool_alloc0 (domain->mp, sizeof (guint8) * (max_interface_id/8 + 1 ));
1580 if (! ARCH_USE_IMT) {
1581 /* initialize interface offsets */
1582 for (i = 0; i < class->interface_offsets_count; ++i) {
1583 int interface_id = class->interfaces_packed [i]->interface_id;
1584 int slot = class->interface_offsets_packed [i];
1585 interface_offsets [class->max_interface_id - interface_id] = &(pvt->vtable [slot]);
1588 for (i = 0; i < class->interface_offsets_count; ++i) {
1589 int interface_id = class->interfaces_packed [i]->interface_id;
1590 pvt->interface_bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
1593 if (extra_interfaces) {
1594 int slot = class->vtable_size;
1600 /* Create trampolines for the methods of the interfaces */
1601 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1602 interf = list_item->data;
1604 if (! ARCH_USE_IMT) {
1605 interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
1607 pvt->interface_bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
1611 while ((cm = mono_class_get_methods (interf, &iter)))
1612 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (cm, target_type);
1614 slot += mono_class_num_methods (interf);
1616 if (! ARCH_USE_IMT) {
1617 g_slist_free (extra_interfaces);
1622 /* Now that the vtable is full, we can actually fill up the IMT */
1623 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
1624 if (extra_interfaces) {
1625 g_slist_free (extra_interfaces);
1633 * mono_class_has_special_static_fields:
1635 * Returns whenever @klass has any thread/context static fields.
1638 mono_class_has_special_static_fields (MonoClass *klass)
1640 MonoClassField *field;
1644 while ((field = mono_class_get_fields (klass, &iter))) {
1645 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1647 if (mono_field_is_deleted (field))
1649 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1650 if (field_is_special_static (klass, field) != SPECIAL_STATIC_NONE)
1659 * create_remote_class_key:
1660 * Creates an array of pointers that can be used as a hash key for a remote class.
1661 * The first element of the array is the number of pointers.
1664 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
1669 if (remote_class == NULL) {
1670 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1671 key = g_malloc (sizeof(gpointer) * 3);
1672 key [0] = GINT_TO_POINTER (2);
1673 key [1] = mono_defaults.marshalbyrefobject_class;
1674 key [2] = extra_class;
1676 key = g_malloc (sizeof(gpointer) * 2);
1677 key [0] = GINT_TO_POINTER (1);
1678 key [1] = extra_class;
1681 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
1682 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
1683 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
1684 key [1] = remote_class->proxy_class;
1686 // Keep the list of interfaces sorted
1687 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
1688 if (extra_class && remote_class->interfaces [i] > extra_class) {
1689 key [j++] = extra_class;
1692 key [j] = remote_class->interfaces [i];
1695 key [j] = extra_class;
1697 // Replace the old class. The interface list is the same
1698 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
1699 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
1700 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
1701 for (i = 0; i < remote_class->interface_count; i++)
1702 key [2 + i] = remote_class->interfaces [i];
1710 * copy_remote_class_key:
1712 * Make a copy of KEY in the mempool MP and return the copy.
1715 copy_remote_class_key (MonoMemPool *mp, gpointer *key)
1717 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
1718 gpointer *mp_key = mono_mempool_alloc (mp, key_size);
1720 memcpy (mp_key, key, key_size);
1726 * mono_remote_class:
1727 * @domain: the application domain
1728 * @class_name: name of the remote class
1730 * Creates and initializes a MonoRemoteClass object for a remote type.
1734 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
1736 MonoRemoteClass *rc;
1737 gpointer* key, *mp_key;
1739 key = create_remote_class_key (NULL, proxy_class);
1741 mono_domain_lock (domain);
1742 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
1746 mono_domain_unlock (domain);
1750 mp_key = copy_remote_class_key (domain->mp, key);
1754 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1755 rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass) + sizeof(MonoClass*));
1756 rc->interface_count = 1;
1757 rc->interfaces [0] = proxy_class;
1758 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
1760 rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass));
1761 rc->interface_count = 0;
1762 rc->proxy_class = proxy_class;
1765 rc->default_vtable = NULL;
1766 rc->xdomain_vtable = NULL;
1767 rc->proxy_class_name = mono_string_to_utf8_mp (domain->mp, class_name);
1769 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
1771 mono_domain_unlock (domain);
1776 * clone_remote_class:
1777 * Creates a copy of the remote_class, adding the provided class or interface
1779 static MonoRemoteClass*
1780 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
1782 MonoRemoteClass *rc;
1783 gpointer* key, *mp_key;
1785 key = create_remote_class_key (remote_class, extra_class);
1786 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
1792 mp_key = copy_remote_class_key (domain->mp, key);
1796 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1798 rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass) + sizeof(MonoClass*) * (remote_class->interface_count + 1));
1799 rc->proxy_class = remote_class->proxy_class;
1800 rc->interface_count = remote_class->interface_count + 1;
1802 // Keep the list of interfaces sorted, since the hash key of
1803 // the remote class depends on this
1804 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
1805 if (remote_class->interfaces [i] > extra_class && i == j)
1806 rc->interfaces [j++] = extra_class;
1807 rc->interfaces [j] = remote_class->interfaces [i];
1810 rc->interfaces [j] = extra_class;
1812 // Replace the old class. The interface array is the same
1813 rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass) + sizeof(MonoClass*) * remote_class->interface_count);
1814 rc->proxy_class = extra_class;
1815 rc->interface_count = remote_class->interface_count;
1816 if (rc->interface_count > 0)
1817 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
1820 rc->default_vtable = NULL;
1821 rc->xdomain_vtable = NULL;
1822 rc->proxy_class_name = remote_class->proxy_class_name;
1824 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
1830 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
1832 mono_domain_lock (domain);
1833 if (rp->target_domain_id != -1) {
1834 if (remote_class->xdomain_vtable == NULL)
1835 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
1836 mono_domain_unlock (domain);
1837 return remote_class->xdomain_vtable;
1839 if (remote_class->default_vtable == NULL) {
1842 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
1843 klass = mono_class_from_mono_type (type);
1844 if ((klass->is_com_object || (mono_defaults.com_object_class && klass == mono_defaults.com_object_class)) && !mono_class_vtable (mono_domain_get (), klass)->remote)
1845 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
1847 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
1850 mono_domain_unlock (domain);
1851 return remote_class->default_vtable;
1855 * mono_upgrade_remote_class:
1856 * @domain: the application domain
1857 * @tproxy: the proxy whose remote class has to be upgraded.
1858 * @klass: class to which the remote class can be casted.
1860 * Updates the vtable of the remote class by adding the necessary method slots
1861 * and interface offsets so it can be safely casted to klass. klass can be a
1862 * class or an interface.
1865 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
1867 MonoTransparentProxy *tproxy;
1868 MonoRemoteClass *remote_class;
1869 gboolean redo_vtable;
1871 mono_domain_lock (domain);
1873 tproxy = (MonoTransparentProxy*) proxy_object;
1874 remote_class = tproxy->remote_class;
1876 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1879 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
1880 if (remote_class->interfaces [i] == klass)
1881 redo_vtable = FALSE;
1884 redo_vtable = (remote_class->proxy_class != klass);
1888 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
1889 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
1892 mono_domain_unlock (domain);
1897 * mono_object_get_virtual_method:
1898 * @obj: object to operate on.
1901 * Retrieves the MonoMethod that would be called on obj if obj is passed as
1902 * the instance of a callvirt of method.
1905 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
1908 MonoMethod **vtable;
1910 MonoMethod *res = NULL;
1912 klass = mono_object_class (obj);
1913 if (klass == mono_defaults.transparent_proxy_class) {
1914 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
1920 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
1923 mono_class_setup_vtable (klass);
1924 vtable = klass->vtable;
1926 /* check method->slot is a valid index: perform isinstance? */
1927 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1929 res = vtable [mono_class_interface_offset (klass, method->klass) + method->slot];
1931 if (method->slot != -1)
1932 res = vtable [method->slot];
1936 if (!res) res = method; /* It may be an interface or abstract class method */
1937 res = mono_marshal_get_remoting_invoke (res);
1946 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
1948 g_error ("runtime invoke called on uninitialized runtime");
1952 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
1955 * mono_runtime_invoke:
1956 * @method: method to invoke
1957 * @obJ: object instance
1958 * @params: arguments to the method
1959 * @exc: exception information.
1961 * Invokes the method represented by @method on the object @obj.
1963 * obj is the 'this' pointer, it should be NULL for static
1964 * methods, a MonoObject* for object instances and a pointer to
1965 * the value type for value types.
1967 * The params array contains the arguments to the method with the
1968 * same convention: MonoObject* pointers for object instances and
1969 * pointers to the value type otherwise.
1971 * From unmanaged code you'll usually use the
1972 * mono_runtime_invoke() variant.
1974 * Note that this function doesn't handle virtual methods for
1975 * you, it will exec the exact method you pass: we still need to
1976 * expose a function to lookup the derived class implementation
1977 * of a virtual method (there are examples of this in the code,
1980 * You can pass NULL as the exc argument if you don't want to
1981 * catch exceptions, otherwise, *exc will be set to the exception
1982 * thrown, if any. if an exception is thrown, you can't use the
1983 * MonoObject* result from the function.
1985 * If the method returns a value type, it is boxed in an object
1989 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
1991 return default_mono_runtime_invoke (method, obj, params, exc);
1995 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
1999 gpointer *p = (gpointer*)dest;
2006 case MONO_TYPE_BOOLEAN:
2008 case MONO_TYPE_U1: {
2009 guint8 *p = (guint8*)dest;
2010 *p = value ? *(guint8*)value : 0;
2015 case MONO_TYPE_CHAR: {
2016 guint16 *p = (guint16*)dest;
2017 *p = value ? *(guint16*)value : 0;
2020 #if SIZEOF_VOID_P == 4
2025 case MONO_TYPE_U4: {
2026 gint32 *p = (gint32*)dest;
2027 *p = value ? *(gint32*)value : 0;
2030 #if SIZEOF_VOID_P == 8
2035 case MONO_TYPE_U8: {
2036 gint64 *p = (gint64*)dest;
2037 *p = value ? *(gint64*)value : 0;
2040 case MONO_TYPE_R4: {
2041 float *p = (float*)dest;
2042 *p = value ? *(float*)value : 0;
2045 case MONO_TYPE_R8: {
2046 double *p = (double*)dest;
2047 *p = value ? *(double*)value : 0;
2050 case MONO_TYPE_STRING:
2051 case MONO_TYPE_SZARRAY:
2052 case MONO_TYPE_CLASS:
2053 case MONO_TYPE_OBJECT:
2054 case MONO_TYPE_ARRAY:
2055 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2057 case MONO_TYPE_FNPTR:
2058 case MONO_TYPE_PTR: {
2059 gpointer *p = (gpointer*)dest;
2060 *p = deref_pointer? *(gpointer*)value: value;
2063 case MONO_TYPE_VALUETYPE:
2064 /* note that 't' and 'type->type' can be different */
2065 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
2066 t = type->data.klass->enum_basetype->type;
2070 size = mono_class_value_size (mono_class_from_mono_type (type), NULL);
2072 memset (dest, 0, size);
2074 memcpy (dest, value, size);
2077 case MONO_TYPE_GENERICINST:
2078 t = type->data.generic_class->container_class->byval_arg.type;
2081 g_warning ("got type %x", type->type);
2082 g_assert_not_reached ();
2087 * mono_field_set_value:
2088 * @obj: Instance object
2089 * @field: MonoClassField describing the field to set
2090 * @value: The value to be set
2092 * Sets the value of the field described by @field in the object instance @obj
2093 * to the value passed in @value. This method should only be used for instance
2094 * fields. For static fields, use mono_field_static_set_value.
2096 * The value must be on the native format of the field type.
2099 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
2103 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2105 dest = (char*)obj + field->offset;
2106 set_value (field->type, dest, value, FALSE);
2110 * mono_field_static_set_value:
2111 * @field: MonoClassField describing the field to set
2112 * @value: The value to be set
2114 * Sets the value of the static field described by @field
2115 * to the value passed in @value.
2117 * The value must be on the native format of the field type.
2120 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
2124 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2125 /* you cant set a constant! */
2126 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
2128 dest = (char*)vt->data + field->offset;
2129 set_value (field->type, dest, value, FALSE);
2132 /* Used by the debugger */
2134 mono_vtable_get_static_field_data (MonoVTable *vt)
2140 * mono_field_get_value:
2141 * @obj: Object instance
2142 * @field: MonoClassField describing the field to fetch information from
2143 * @value: pointer to the location where the value will be stored
2145 * Use this routine to get the value of the field @field in the object
2148 * The pointer provided by value must be of the field type, for reference
2149 * types this is a MonoObject*, for value types its the actual pointer to
2154 * mono_field_get_value (obj, int_field, &i);
2157 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
2161 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2163 src = (char*)obj + field->offset;
2164 set_value (field->type, value, src, TRUE);
2168 * mono_field_get_value_object:
2169 * @domain: domain where the object will be created (if boxing)
2170 * @field: MonoClassField describing the field to fetch information from
2171 * @obj: The object instance for the field.
2173 * Returns: a new MonoObject with the value from the given field. If the
2174 * field represents a value type, the value is boxed.
2178 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
2182 MonoVTable *vtable = NULL;
2184 gboolean is_static = FALSE;
2185 gboolean is_ref = FALSE;
2187 switch (field->type->type) {
2188 case MONO_TYPE_STRING:
2189 case MONO_TYPE_OBJECT:
2190 case MONO_TYPE_CLASS:
2191 case MONO_TYPE_ARRAY:
2192 case MONO_TYPE_SZARRAY:
2197 case MONO_TYPE_BOOLEAN:
2200 case MONO_TYPE_CHAR:
2209 case MONO_TYPE_VALUETYPE:
2210 is_ref = field->type->byref;
2212 case MONO_TYPE_GENERICINST:
2213 is_ref = !field->type->data.generic_class->container_class->valuetype;
2216 g_error ("type 0x%x not handled in "
2217 "mono_field_get_value_object", field->type->type);
2221 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
2223 vtable = mono_class_vtable (domain, field->parent);
2224 if (!vtable->initialized)
2225 mono_runtime_class_init (vtable);
2230 mono_field_static_get_value (vtable, field, &o);
2232 mono_field_get_value (obj, field, &o);
2237 /* boxed value type */
2238 klass = mono_class_from_mono_type (field->type);
2239 o = mono_object_new (domain, klass);
2240 v = ((gchar *) o) + sizeof (MonoObject);
2242 mono_field_static_get_value (vtable, field, v);
2244 mono_field_get_value (obj, field, v);
2251 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
2254 const char *p = blob;
2255 mono_metadata_decode_blob_size (p, &p);
2258 case MONO_TYPE_BOOLEAN:
2261 *(guint8 *) value = *p;
2263 case MONO_TYPE_CHAR:
2266 *(guint16*) value = read16 (p);
2270 *(guint32*) value = read32 (p);
2274 *(guint64*) value = read64 (p);
2277 readr4 (p, (float*) value);
2280 readr8 (p, (double*) value);
2282 case MONO_TYPE_STRING:
2283 *(gpointer*) value = mono_ldstr_metdata_sig (domain, blob);
2285 case MONO_TYPE_CLASS:
2286 *(gpointer*) value = NULL;
2290 g_warning ("type 0x%02x should not be in constant table", type);
2296 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
2298 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT);
2299 mono_get_constant_value_from_blob (domain, field->def_type, field->data, value);
2303 * mono_field_static_get_value:
2304 * @vt: vtable to the object
2305 * @field: MonoClassField describing the field to fetch information from
2306 * @value: where the value is returned
2308 * Use this routine to get the value of the static field @field value.
2310 * The pointer provided by value must be of the field type, for reference
2311 * types this is a MonoObject*, for value types its the actual pointer to
2316 * mono_field_static_get_value (vt, int_field, &i);
2319 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
2323 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2325 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
2326 get_default_field_value (vt->domain, field, value);
2330 src = (char*)vt->data + field->offset;
2331 set_value (field->type, value, src, TRUE);
2335 * mono_property_set_value:
2336 * @prop: MonoProperty to set
2337 * @obj: instance object on which to act
2338 * @params: parameters to pass to the propery
2339 * @exc: optional exception
2341 * Invokes the property's set method with the given arguments on the
2342 * object instance obj (or NULL for static properties).
2344 * You can pass NULL as the exc argument if you don't want to
2345 * catch exceptions, otherwise, *exc will be set to the exception
2346 * thrown, if any. if an exception is thrown, you can't use the
2347 * MonoObject* result from the function.
2350 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
2352 default_mono_runtime_invoke (prop->set, obj, params, exc);
2356 * mono_property_get_value:
2357 * @prop: MonoProperty to fetch
2358 * @obj: instance object on which to act
2359 * @params: parameters to pass to the propery
2360 * @exc: optional exception
2362 * Invokes the property's get method with the given arguments on the
2363 * object instance obj (or NULL for static properties).
2365 * You can pass NULL as the exc argument if you don't want to
2366 * catch exceptions, otherwise, *exc will be set to the exception
2367 * thrown, if any. if an exception is thrown, you can't use the
2368 * MonoObject* result from the function.
2370 * Returns: the value from invoking the get method on the property.
2373 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
2375 return default_mono_runtime_invoke (prop->get, obj, params, exc);
2379 * mono_nullable_init:
2380 * @buf: The nullable structure to initialize.
2381 * @value: the value to initialize from
2382 * @klass: the type for the object
2384 * Initialize the nullable structure pointed to by @buf from @value which
2385 * should be a boxed value type. The size of @buf should be able to hold
2386 * as much data as the @klass->instance_size (which is the number of bytes
2387 * that will be copies).
2389 * Since Nullables have variable structure, we can not define a C
2390 * structure for them.
2393 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
2395 MonoClass *param_class = klass->cast_class;
2397 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
2398 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
2400 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
2402 memcpy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
2404 memset (buf + klass->fields [0].offset - sizeof (MonoObject), 0, mono_class_value_size (param_class, NULL));
2408 * mono_nullable_box:
2409 * @buf: The buffer representing the data to be boxed
2410 * @klass: the type to box it as.
2412 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
2416 mono_nullable_box (guint8 *buf, MonoClass *klass)
2418 MonoClass *param_class = klass->cast_class;
2420 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
2421 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
2423 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
2424 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
2425 memcpy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
2433 * mono_get_delegate_invoke:
2434 * @klass: The delegate class
2436 * Returns: the MonoMethod for the "Invoke" method in the delegate klass
2439 mono_get_delegate_invoke (MonoClass *klass)
2443 im = mono_class_get_method_from_name (klass, "Invoke", -1);
2450 * mono_runtime_delegate_invoke:
2451 * @delegate: pointer to a delegate object.
2452 * @params: parameters for the delegate.
2453 * @exc: Pointer to the exception result.
2455 * Invokes the delegate method @delegate with the parameters provided.
2457 * You can pass NULL as the exc argument if you don't want to
2458 * catch exceptions, otherwise, *exc will be set to the exception
2459 * thrown, if any. if an exception is thrown, you can't use the
2460 * MonoObject* result from the function.
2463 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
2467 im = mono_get_delegate_invoke (delegate->vtable->klass);
2470 return mono_runtime_invoke (im, delegate, params, exc);
2473 static char **main_args = NULL;
2474 static int num_main_args;
2477 * mono_runtime_get_main_args:
2479 * Returns: a MonoArray with the arguments passed to the main program
2482 mono_runtime_get_main_args (void)
2486 MonoDomain *domain = mono_domain_get ();
2491 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
2493 for (i = 0; i < num_main_args; ++i)
2494 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
2500 fire_process_exit_event (void)
2502 MonoClassField *field;
2503 MonoDomain *domain = mono_domain_get ();
2505 MonoObject *delegate, *exc;
2507 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "ProcessExit");
2510 if (domain != mono_get_root_domain ())
2513 delegate = *(MonoObject **)(((char *)domain->domain) + field->offset);
2514 if (delegate == NULL)
2519 mono_runtime_delegate_invoke (delegate, pa, &exc);
2523 * mono_runtime_run_main:
2524 * @method: the method to start the application with (usually Main)
2525 * @argc: number of arguments from the command line
2526 * @argv: array of strings from the command line
2527 * @exc: excetption results
2529 * Execute a standard Main() method (argc/argv contains the
2530 * executable name). This method also sets the command line argument value
2531 * needed by System.Environment.
2536 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
2540 MonoArray *args = NULL;
2541 MonoDomain *domain = mono_domain_get ();
2542 gchar *utf8_fullpath;
2545 g_assert (method != NULL);
2547 mono_thread_set_main (mono_thread_current ());
2549 main_args = g_new0 (char*, argc);
2550 num_main_args = argc;
2552 if (!g_path_is_absolute (argv [0])) {
2553 gchar *basename = g_path_get_basename (argv [0]);
2554 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
2558 utf8_fullpath = mono_utf8_from_external (fullpath);
2559 if(utf8_fullpath == NULL) {
2560 /* Printing the arg text will cause glib to
2561 * whinge about "Invalid UTF-8", but at least
2562 * its relevant, and shows the problem text
2565 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
2566 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
2573 utf8_fullpath = mono_utf8_from_external (argv[0]);
2574 if(utf8_fullpath == NULL) {
2575 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
2576 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
2581 main_args [0] = utf8_fullpath;
2583 for (i = 1; i < argc; ++i) {
2586 utf8_arg=mono_utf8_from_external (argv[i]);
2587 if(utf8_arg==NULL) {
2588 /* Ditto the comment about Invalid UTF-8 here */
2589 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
2590 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
2594 main_args [i] = utf8_arg;
2598 if (mono_method_signature (method)->param_count) {
2599 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
2600 for (i = 0; i < argc; ++i) {
2601 /* The encodings should all work, given that
2602 * we've checked all these args for the
2605 gchar *str = mono_utf8_from_external (argv [i]);
2606 MonoString *arg = mono_string_new (domain, str);
2607 mono_array_setref (args, i, arg);
2611 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
2614 mono_assembly_set_main (method->klass->image->assembly);
2616 result = mono_runtime_exec_main (method, args, exc);
2617 fire_process_exit_event ();
2621 /* Used in mono_unhandled_exception */
2623 create_unhandled_exception_eventargs (MonoObject *exc)
2627 MonoMethod *method = NULL;
2628 MonoBoolean is_terminating = TRUE;
2631 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
2634 mono_class_init (klass);
2636 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
2637 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
2641 args [1] = &is_terminating;
2643 obj = mono_object_new (mono_domain_get (), klass);
2644 mono_runtime_invoke (method, obj, args, NULL);
2650 * mono_unhandled_exception:
2651 * @exc: exception thrown
2653 * This is a VM internal routine.
2655 * We call this function when we detect an unhandled exception
2656 * in the default domain.
2658 * It invokes the * UnhandledException event in AppDomain or prints
2659 * a warning to the console
2662 mono_unhandled_exception (MonoObject *exc)
2664 MonoDomain *domain = mono_domain_get ();
2665 MonoClassField *field;
2666 MonoObject *delegate;
2668 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
2669 "UnhandledException");
2672 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
2673 delegate = *(MonoObject **)(((char *)domain->domain) + field->offset);
2675 /* set exitcode only in the main thread */
2676 if (mono_thread_current () == main_thread)
2677 mono_environment_exitcode_set (1);
2678 if (domain != mono_get_root_domain () || !delegate) {
2679 mono_print_unhandled_exception (exc);
2681 MonoObject *e = NULL;
2684 pa [0] = domain->domain;
2685 pa [1] = create_unhandled_exception_eventargs (exc);
2686 mono_runtime_delegate_invoke (delegate, pa, &e);
2689 gchar *msg = mono_string_to_utf8 (((MonoException *) e)->message);
2690 g_warning ("exception inside UnhandledException handler: %s\n", msg);
2698 * Launch a new thread to execute a function
2700 * main_func is called back from the thread with main_args as the
2701 * parameter. The callback function is expected to start Main()
2702 * eventually. This function then waits for all managed threads to
2704 * It is not necesseray anymore to execute managed code in a subthread,
2705 * so this function should not be used anymore by default: just
2706 * execute the code and then call mono_thread_manage ().
2709 mono_runtime_exec_managed_code (MonoDomain *domain,
2710 MonoMainThreadFunc main_func,
2713 mono_thread_create (domain, main_func, main_args);
2715 mono_thread_manage ();
2719 * Execute a standard Main() method (args doesn't contain the
2723 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
2728 MonoCustomAttrInfo* cinfo;
2729 gboolean has_stathread_attribute;
2730 MonoThread* thread = mono_thread_current ();
2736 domain = mono_object_domain (args);
2737 if (!domain->entry_assembly) {
2739 MonoAssembly *assembly;
2741 assembly = method->klass->image->assembly;
2742 domain->entry_assembly = assembly;
2743 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
2745 str = g_strconcat (assembly->image->name, ".config", NULL);
2746 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
2750 cinfo = mono_custom_attrs_from_method (method);
2752 static MonoClass *stathread_attribute = NULL;
2753 if (!stathread_attribute)
2754 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
2755 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
2757 mono_custom_attrs_free (cinfo);
2759 has_stathread_attribute = FALSE;
2761 if (has_stathread_attribute) {
2762 thread->apartment_state = ThreadApartmentState_STA;
2763 } else if (mono_get_runtime_info ()->framework_version [0] == '1') {
2764 thread->apartment_state = ThreadApartmentState_Unknown;
2766 thread->apartment_state = ThreadApartmentState_MTA;
2768 mono_thread_init_apartment_state ();
2770 /* FIXME: check signature of method */
2771 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
2773 res = mono_runtime_invoke (method, NULL, pa, exc);
2775 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
2779 mono_environment_exitcode_set (rval);
2781 mono_runtime_invoke (method, NULL, pa, exc);
2785 /* If the return type of Main is void, only
2786 * set the exitcode if an exception was thrown
2787 * (we don't want to blow away an
2788 * explicitly-set exit code)
2791 mono_environment_exitcode_set (rval);
2799 * mono_install_runtime_invoke:
2800 * @func: Function to install
2802 * This is a VM internal routine
2805 mono_install_runtime_invoke (MonoInvokeFunc func)
2807 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
2811 * mono_runtime_invoke_array:
2812 * @method: method to invoke
2813 * @obJ: object instance
2814 * @params: arguments to the method
2815 * @exc: exception information.
2817 * Invokes the method represented by @method on the object @obj.
2819 * obj is the 'this' pointer, it should be NULL for static
2820 * methods, a MonoObject* for object instances and a pointer to
2821 * the value type for value types.
2823 * The params array contains the arguments to the method with the
2824 * same convention: MonoObject* pointers for object instances and
2825 * pointers to the value type otherwise. The _invoke_array
2826 * variant takes a C# object[] as the params argument (MonoArray
2827 * *params): in this case the value types are boxed inside the
2828 * respective reference representation.
2830 * From unmanaged code you'll usually use the
2831 * mono_runtime_invoke() variant.
2833 * Note that this function doesn't handle virtual methods for
2834 * you, it will exec the exact method you pass: we still need to
2835 * expose a function to lookup the derived class implementation
2836 * of a virtual method (there are examples of this in the code,
2839 * You can pass NULL as the exc argument if you don't want to
2840 * catch exceptions, otherwise, *exc will be set to the exception
2841 * thrown, if any. if an exception is thrown, you can't use the
2842 * MonoObject* result from the function.
2844 * If the method returns a value type, it is boxed in an object
2848 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
2851 MonoMethodSignature *sig = mono_method_signature (method);
2852 gpointer *pa = NULL;
2855 if (NULL != params) {
2856 pa = alloca (sizeof (gpointer) * mono_array_length (params));
2857 for (i = 0; i < mono_array_length (params); i++) {
2858 MonoType *t = sig->params [i];
2864 case MONO_TYPE_BOOLEAN:
2867 case MONO_TYPE_CHAR:
2876 case MONO_TYPE_VALUETYPE:
2877 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
2880 g_assert_not_reached ();
2881 /* The runtime invoke wrapper needs the original boxed vtype */
2882 pa [i] = mono_array_get (params, MonoObject*, i);
2884 /* MS seems to create the objects if a null is passed in */
2885 if (!mono_array_get (params, MonoObject*, i))
2886 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
2890 * We can't pass the unboxed vtype byref to the callee, since
2891 * that would mean the callee would be able to modify boxed
2892 * primitive types. So we (and MS) make a copy of the boxed
2893 * object, pass that to the callee, and replace the original
2894 * boxed object in the arg array with the copy.
2896 MonoObject *orig = mono_array_get (params, MonoObject*, i);
2897 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
2898 mono_array_setref (params, i, copy);
2901 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
2904 case MONO_TYPE_STRING:
2905 case MONO_TYPE_OBJECT:
2906 case MONO_TYPE_CLASS:
2907 case MONO_TYPE_ARRAY:
2908 case MONO_TYPE_SZARRAY:
2910 pa [i] = mono_array_addr (params, MonoObject*, i);
2912 pa [i] = mono_array_get (params, MonoObject*, i);
2914 case MONO_TYPE_GENERICINST:
2916 t = &t->data.generic_class->container_class->this_arg;
2918 t = &t->data.generic_class->container_class->byval_arg;
2921 g_error ("type 0x%x not handled in ves_icall_InternalInvoke", sig->params [i]->type);
2926 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
2929 if (mono_class_is_nullable (method->klass)) {
2930 /* Need to create a boxed vtype instead */
2936 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
2940 obj = mono_object_new (mono_domain_get (), method->klass);
2941 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
2942 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
2944 if (method->klass->valuetype)
2945 o = mono_object_unbox (obj);
2948 } else if (method->klass->valuetype) {
2949 obj = mono_value_box (mono_domain_get (), method->klass, obj);
2952 mono_runtime_invoke (method, o, pa, exc);
2955 if (mono_class_is_nullable (method->klass)) {
2956 MonoObject *nullable;
2958 /* Convert the unboxed vtype into a Nullable structure */
2959 nullable = mono_object_new (mono_domain_get (), method->klass);
2961 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
2962 obj = mono_object_unbox (nullable);
2965 /* obj must be already unboxed if needed */
2966 return mono_runtime_invoke (method, obj, pa, exc);
2971 arith_overflow (void)
2973 mono_raise_exception (mono_get_exception_overflow ());
2977 * mono_object_allocate:
2978 * @size: number of bytes to allocate
2980 * This is a very simplistic routine until we have our GC-aware
2983 * Returns: an allocated object of size @size, or NULL on failure.
2985 static inline void *
2986 mono_object_allocate (size_t size, MonoVTable *vtable)
2989 mono_stats.new_object_count++;
2990 ALLOC_OBJECT (o, vtable, size);
2996 * mono_object_allocate_ptrfree:
2997 * @size: number of bytes to allocate
2999 * Note that the memory allocated is not zeroed.
3000 * Returns: an allocated object of size @size, or NULL on failure.
3002 static inline void *
3003 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
3006 mono_stats.new_object_count++;
3007 ALLOC_PTRFREE (o, vtable, size);
3011 static inline void *
3012 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
3015 ALLOC_TYPED (o, size, vtable);
3016 mono_stats.new_object_count++;
3023 * @klass: the class of the object that we want to create
3025 * Returns: a newly created object whose definition is
3026 * looked up using @klass. This will not invoke any constructors,
3027 * so the consumer of this routine has to invoke any constructors on
3028 * its own to initialize the object.
3031 mono_object_new (MonoDomain *domain, MonoClass *klass)
3033 MONO_ARCH_SAVE_REGS;
3034 return mono_object_new_specific (mono_class_vtable (domain, klass));
3038 * mono_object_new_specific:
3039 * @vtable: the vtable of the object that we want to create
3041 * Returns: A newly created object with class and domain specified
3045 mono_object_new_specific (MonoVTable *vtable)
3049 MONO_ARCH_SAVE_REGS;
3051 /* check for is_com_object for COM Interop */
3052 if (vtable->remote || vtable->klass->is_com_object)
3055 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
3058 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
3061 mono_class_init (klass);
3063 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
3065 vtable->domain->create_proxy_for_type_method = im;
3068 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
3070 o = mono_runtime_invoke (im, NULL, pa, NULL);
3071 if (o != NULL) return o;
3074 return mono_object_new_alloc_specific (vtable);
3078 mono_object_new_alloc_specific (MonoVTable *vtable)
3082 if (!vtable->klass->has_references) {
3083 o = mono_object_new_ptrfree (vtable);
3084 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3085 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
3087 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
3088 o = mono_object_allocate (vtable->klass->instance_size, vtable);
3090 if (vtable->klass->has_finalize)
3091 mono_object_register_finalizer (o);
3093 mono_profiler_allocation (o, vtable->klass);
3098 mono_object_new_fast (MonoVTable *vtable)
3101 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
3106 mono_object_new_ptrfree (MonoVTable *vtable)
3109 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
3110 #if NEED_TO_ZERO_PTRFREE
3111 /* an inline memset is much faster for the common vcase of small objects
3112 * note we assume the allocated size is a multiple of sizeof (void*).
3114 if (vtable->klass->instance_size < 128) {
3116 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
3117 p = (gpointer*)((char*)obj + sizeof (MonoObject));
3123 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
3130 mono_object_new_ptrfree_box (MonoVTable *vtable)
3133 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
3134 /* the object will be boxed right away, no need to memzero it */
3139 * mono_class_get_allocation_ftn:
3141 * @for_box: the object will be used for boxing
3142 * @pass_size_in_words:
3144 * Return the allocation function appropriate for the given class.
3148 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
3150 *pass_size_in_words = FALSE;
3152 if (vtable->klass->has_finalize || vtable->klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
3153 return mono_object_new_specific;
3155 if (!vtable->klass->has_references) {
3156 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
3158 return mono_object_new_ptrfree_box;
3159 return mono_object_new_ptrfree;
3162 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3164 return mono_object_new_fast;
3167 * FIXME: This is actually slower than mono_object_new_fast, because
3168 * of the overhead of parameter passing.
3171 *pass_size_in_words = TRUE;
3172 #ifdef GC_REDIRECT_TO_LOCAL
3173 return GC_local_gcj_fast_malloc;
3175 return GC_gcj_fast_malloc;
3180 return mono_object_new_specific;
3184 * mono_object_new_from_token:
3185 * @image: Context where the type_token is hosted
3186 * @token: a token of the type that we want to create
3188 * Returns: A newly created object whose definition is
3189 * looked up using @token in the @image image
3192 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
3196 class = mono_class_get (image, token);
3198 return mono_object_new (domain, class);
3203 * mono_object_clone:
3204 * @obj: the object to clone
3206 * Returns: A newly created object who is a shallow copy of @obj
3209 mono_object_clone (MonoObject *obj)
3214 size = obj->vtable->klass->instance_size;
3215 o = mono_object_allocate (size, obj->vtable);
3216 /* do not copy the sync state */
3217 memcpy ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
3220 if (obj->vtable->klass->has_references)
3221 mono_gc_wbarrier_object (o);
3223 mono_profiler_allocation (o, obj->vtable->klass);
3225 if (obj->vtable->klass->has_finalize)
3226 mono_object_register_finalizer (o);
3231 * mono_array_full_copy:
3232 * @src: source array to copy
3233 * @dest: destination array
3235 * Copies the content of one array to another with exactly the same type and size.
3238 mono_array_full_copy (MonoArray *src, MonoArray *dest)
3241 MonoClass *klass = src->obj.vtable->klass;
3243 MONO_ARCH_SAVE_REGS;
3245 g_assert (klass == dest->obj.vtable->klass);
3247 size = mono_array_length (src);
3248 g_assert (size == mono_array_length (dest));
3249 size *= mono_array_element_size (klass);
3251 if (klass->valuetype) {
3252 if (klass->has_references)
3253 mono_value_copy_array (dest, 0, src, mono_array_length (src));
3255 memcpy (&dest->vector, &src->vector, size);
3257 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
3260 memcpy (&dest->vector, &src->vector, size);
3265 * mono_array_clone_in_domain:
3266 * @domain: the domain in which the array will be cloned into
3267 * @array: the array to clone
3269 * This routine returns a copy of the array that is hosted on the
3270 * specified MonoDomain.
3273 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
3278 MonoClass *klass = array->obj.vtable->klass;
3280 MONO_ARCH_SAVE_REGS;
3282 if (array->bounds == NULL) {
3283 size = mono_array_length (array);
3284 o = mono_array_new_full (domain, klass, &size, NULL);
3286 size *= mono_array_element_size (klass);
3288 if (klass->valuetype) {
3289 if (klass->has_references)
3290 mono_value_copy_array (o, 0, array, mono_array_length (array));
3292 memcpy (&o->vector, &array->vector, size);
3294 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
3297 memcpy (&o->vector, &array->vector, size);
3302 sizes = alloca (klass->rank * sizeof(guint32) * 2);
3303 size = mono_array_element_size (klass);
3304 for (i = 0; i < klass->rank; ++i) {
3305 sizes [i] = array->bounds [i].length;
3306 size *= array->bounds [i].length;
3307 sizes [i + klass->rank] = array->bounds [i].lower_bound;
3309 o = mono_array_new_full (domain, klass, sizes, sizes + klass->rank);
3311 if (klass->valuetype) {
3312 if (klass->has_references)
3313 mono_value_copy_array (o, 0, array, mono_array_length (array));
3315 memcpy (&o->vector, &array->vector, size);
3317 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
3320 memcpy (&o->vector, &array->vector, size);
3328 * @array: the array to clone
3330 * Returns: A newly created array who is a shallow copy of @array
3333 mono_array_clone (MonoArray *array)
3335 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
3338 /* helper macros to check for overflow when calculating the size of arrays */
3339 #define MYGUINT32_MAX 4294967295U
3340 #define CHECK_ADD_OVERFLOW_UN(a,b) \
3341 (guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a) ? -1 : 0
3342 #define CHECK_MUL_OVERFLOW_UN(a,b) \
3343 ((guint32)(a) == 0) || ((guint32)(b) == 0) ? 0 : \
3344 (guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a))
3347 * mono_array_new_full:
3348 * @domain: domain where the object is created
3349 * @array_class: array class
3350 * @lengths: lengths for each dimension in the array
3351 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
3353 * This routine creates a new array objects with the given dimensions,
3354 * lower bounds and type.
3357 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, guint32 *lengths, guint32 *lower_bounds)
3359 guint32 byte_len, len, bounds_size;
3365 if (!array_class->inited)
3366 mono_class_init (array_class);
3368 byte_len = mono_array_element_size (array_class);
3371 /* A single dimensional array with a 0 lower bound is the same as an szarray */
3372 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
3378 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
3380 for (i = 0; i < array_class->rank; ++i) {
3381 if ((int) lengths [i] < 0)
3383 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
3384 mono_gc_out_of_memory (MYGUINT32_MAX);
3389 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
3390 mono_gc_out_of_memory (MYGUINT32_MAX);
3392 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
3393 mono_gc_out_of_memory (MYGUINT32_MAX);
3394 byte_len += sizeof (MonoArray);
3397 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
3398 mono_gc_out_of_memory (MYGUINT32_MAX);
3399 byte_len = (byte_len + 3) & ~3;
3400 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
3401 mono_gc_out_of_memory (MYGUINT32_MAX);
3402 byte_len += bounds_size;
3405 * Following three lines almost taken from mono_object_new ():
3406 * they need to be kept in sync.
3408 vtable = mono_class_vtable (domain, array_class);
3409 if (!array_class->has_references) {
3410 o = mono_object_allocate_ptrfree (byte_len, vtable);
3411 #if NEED_TO_ZERO_PTRFREE
3412 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
3414 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3415 o = mono_object_allocate_spec (byte_len, vtable);
3417 o = mono_object_allocate (byte_len, vtable);
3420 array = (MonoArray*)o;
3421 array->max_length = len;
3424 MonoArrayBounds *bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
3425 array->bounds = bounds;
3426 for (i = 0; i < array_class->rank; ++i) {
3427 bounds [i].length = lengths [i];
3429 bounds [i].lower_bound = lower_bounds [i];
3433 mono_profiler_allocation (o, array_class);
3440 * @domain: domain where the object is created
3441 * @eclass: element class
3442 * @n: number of array elements
3444 * This routine creates a new szarray with @n elements of type @eclass.
3447 mono_array_new (MonoDomain *domain, MonoClass *eclass, guint32 n)
3451 MONO_ARCH_SAVE_REGS;
3453 ac = mono_array_class_get (eclass, 1);
3454 g_assert (ac != NULL);
3456 return mono_array_new_specific (mono_class_vtable (domain, ac), n);
3460 * mono_array_new_specific:
3461 * @vtable: a vtable in the appropriate domain for an initialized class
3462 * @n: number of array elements
3464 * This routine is a fast alternative to mono_array_new() for code which
3465 * can be sure about the domain it operates in.
3468 mono_array_new_specific (MonoVTable *vtable, guint32 n)
3472 guint32 byte_len, elem_size;
3474 MONO_ARCH_SAVE_REGS;
3479 elem_size = mono_array_element_size (vtable->klass);
3480 if (CHECK_MUL_OVERFLOW_UN (n, elem_size))
3481 mono_gc_out_of_memory (MYGUINT32_MAX);
3482 byte_len = n * elem_size;
3483 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
3484 mono_gc_out_of_memory (MYGUINT32_MAX);
3485 byte_len += sizeof (MonoArray);
3486 if (!vtable->klass->has_references) {
3487 o = mono_object_allocate_ptrfree (byte_len, vtable);
3488 #if NEED_TO_ZERO_PTRFREE
3489 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
3491 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3492 o = mono_object_allocate_spec (byte_len, vtable);
3494 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
3495 o = mono_object_allocate (byte_len, vtable);
3498 ao = (MonoArray *)o;
3501 mono_profiler_allocation (o, vtable->klass);
3507 * mono_string_new_utf16:
3508 * @text: a pointer to an utf16 string
3509 * @len: the length of the string
3511 * Returns: A newly created string object which contains @text.
3514 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
3518 s = mono_string_new_size (domain, len);
3519 g_assert (s != NULL);
3521 memcpy (mono_string_chars (s), text, len * 2);
3527 * mono_string_new_size:
3528 * @text: a pointer to an utf16 string
3529 * @len: the length of the string
3531 * Returns: A newly created string object of @len
3534 mono_string_new_size (MonoDomain *domain, gint32 len)
3538 size_t size = (sizeof (MonoString) + ((len + 1) * 2));
3540 /* overflow ? can't fit it, can't allocate it! */
3542 mono_gc_out_of_memory (-1);
3544 vtable = mono_class_vtable (domain, mono_defaults.string_class);
3546 s = mono_object_allocate_ptrfree (size, vtable);
3549 #if NEED_TO_ZERO_PTRFREE
3552 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
3558 * mono_string_new_len:
3559 * @text: a pointer to an utf8 string
3560 * @length: number of bytes in @text to consider
3562 * Returns: A newly created string object which contains @text.
3565 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
3567 GError *error = NULL;
3568 MonoString *o = NULL;
3570 glong items_written;
3572 ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
3575 o = mono_string_new_utf16 (domain, ut, items_written);
3577 g_error_free (error);
3586 * @text: a pointer to an utf8 string
3588 * Returns: A newly created string object which contains @text.
3591 mono_string_new (MonoDomain *domain, const char *text)
3593 GError *error = NULL;
3594 MonoString *o = NULL;
3596 glong items_written;
3601 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
3604 o = mono_string_new_utf16 (domain, ut, items_written);
3606 g_error_free (error);
3614 * mono_string_new_wrapper:
3615 * @text: pointer to utf8 characters.
3617 * Helper function to create a string object from @text in the current domain.
3620 mono_string_new_wrapper (const char *text)
3622 MonoDomain *domain = mono_domain_get ();
3624 MONO_ARCH_SAVE_REGS;
3627 return mono_string_new (domain, text);
3634 * @class: the class of the value
3635 * @value: a pointer to the unboxed data
3637 * Returns: A newly created object which contains @value.
3640 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
3646 g_assert (class->valuetype);
3648 vtable = mono_class_vtable (domain, class);
3649 size = mono_class_instance_size (class);
3650 res = mono_object_allocate (size, vtable);
3651 mono_profiler_allocation (res, class);
3653 size = size - sizeof (MonoObject);
3656 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
3659 #if NO_UNALIGNED_ACCESS
3660 memcpy ((char *)res + sizeof (MonoObject), value, size);
3664 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
3667 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
3670 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
3673 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
3676 memcpy ((char *)res + sizeof (MonoObject), value, size);
3679 if (class->has_finalize)
3680 mono_object_register_finalizer (res);
3686 * @dest: destination pointer
3687 * @src: source pointer
3688 * @klass: a valuetype class
3690 * Copy a valuetype from @src to @dest. This function must be used
3691 * when @klass contains references fields.
3694 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
3696 int size = mono_class_value_size (klass, NULL);
3697 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
3698 memcpy (dest, src, size);
3702 * mono_value_copy_array:
3703 * @dest: destination array
3704 * @dest_idx: index in the @dest array
3705 * @src: source pointer
3706 * @count: number of items
3708 * Copy @count valuetype items from @src to @dest. This function must be used
3709 * when @klass contains references fields.
3710 * Overlap is handled.
3713 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
3715 int size = mono_array_element_size (dest->obj.vtable->klass);
3716 char *d = mono_array_addr_with_size (dest, size, dest_idx);
3717 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
3718 memmove (d, src, size * count);
3722 * mono_object_get_domain:
3723 * @obj: object to query
3725 * Returns: the MonoDomain where the object is hosted
3728 mono_object_get_domain (MonoObject *obj)
3730 return mono_object_domain (obj);
3734 * mono_object_get_class:
3735 * @obj: object to query
3737 * Returns: the MonOClass of the object.
3740 mono_object_get_class (MonoObject *obj)
3742 return mono_object_class (obj);
3745 * mono_object_get_size:
3746 * @o: object to query
3748 * Returns: the size, in bytes, of @o
3751 mono_object_get_size (MonoObject* o)
3753 MonoClass* klass = mono_object_class (o);
3754 if (klass == mono_defaults.string_class) {
3755 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
3756 } else if (o->vtable->rank) {
3757 MonoArray *array = (MonoArray*)o;
3758 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
3759 if (array->bounds) {
3762 size += sizeof (MonoArrayBounds) * o->vtable->rank;
3766 return mono_class_instance_size (klass);
3771 * mono_object_unbox:
3772 * @obj: object to unbox
3774 * Returns: a pointer to the start of the valuetype boxed in this
3777 * This method will assert if the object passed is not a valuetype.
3780 mono_object_unbox (MonoObject *obj)
3782 /* add assert for valuetypes? */
3783 g_assert (obj->vtable->klass->valuetype);
3784 return ((char*)obj) + sizeof (MonoObject);
3788 * mono_object_isinst:
3790 * @klass: a pointer to a class
3792 * Returns: @obj if @obj is derived from @klass
3795 mono_object_isinst (MonoObject *obj, MonoClass *klass)
3798 mono_class_init (klass);
3800 if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE)
3801 return mono_object_isinst_mbyref (obj, klass);
3806 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
3810 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
3819 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
3820 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
3824 MonoClass *oklass = vt->klass;
3825 if ((oklass == mono_defaults.transparent_proxy_class))
3826 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
3828 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
3832 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
3834 MonoDomain *domain = mono_domain_get ();
3836 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
3837 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
3838 MonoMethod *im = NULL;
3841 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
3842 im = mono_object_get_virtual_method (rp, im);
3845 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
3848 res = mono_runtime_invoke (im, rp, pa, NULL);
3850 if (*(MonoBoolean *) mono_object_unbox(res)) {
3851 /* Update the vtable of the remote type, so it can safely cast to this new type */
3852 mono_upgrade_remote_class (domain, obj, klass);
3861 * mono_object_castclass_mbyref:
3863 * @klass: a pointer to a class
3865 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
3868 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
3870 if (!obj) return NULL;
3871 if (mono_object_isinst_mbyref (obj, klass)) return obj;
3873 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
3875 "InvalidCastException"));
3880 MonoDomain *orig_domain;
3886 str_lookup (MonoDomain *domain, gpointer user_data)
3888 LDStrInfo *info = user_data;
3889 if (info->res || domain == info->orig_domain)
3891 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
3897 mono_string_get_pinned (MonoString *str)
3901 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
3902 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
3903 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
3904 news->length = mono_string_length (str);
3909 #define mono_string_get_pinned(str) (str)
3913 mono_string_is_interned_lookup (MonoString *str, int insert)
3915 MonoGHashTable *ldstr_table;
3919 domain = ((MonoObject *)str)->vtable->domain;
3920 ldstr_table = domain->ldstr_table;
3922 if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
3927 str = mono_string_get_pinned (str);
3928 mono_g_hash_table_insert (ldstr_table, str, str);
3932 LDStrInfo ldstr_info;
3933 ldstr_info.orig_domain = domain;
3934 ldstr_info.ins = str;
3935 ldstr_info.res = NULL;
3937 mono_domain_foreach (str_lookup, &ldstr_info);
3938 if (ldstr_info.res) {
3940 * the string was already interned in some other domain:
3941 * intern it in the current one as well.
3943 mono_g_hash_table_insert (ldstr_table, str, str);
3953 * mono_string_is_interned:
3954 * @o: String to probe
3956 * Returns whether the string has been interned.
3959 mono_string_is_interned (MonoString *o)
3961 return mono_string_is_interned_lookup (o, FALSE);
3965 * mono_string_intern:
3966 * @o: String to intern
3968 * Interns the string passed.
3969 * Returns: The interned string.
3972 mono_string_intern (MonoString *str)
3974 return mono_string_is_interned_lookup (str, TRUE);
3979 * @domain: the domain where the string will be used.
3980 * @image: a metadata context
3981 * @idx: index into the user string table.
3983 * Implementation for the ldstr opcode.
3984 * Returns: a loaded string from the @image/@idx combination.
3987 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
3989 MONO_ARCH_SAVE_REGS;
3992 return mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx);
3994 return mono_ldstr_metdata_sig (domain, mono_metadata_user_string (image, idx));
3998 * mono_ldstr_metdata_sig
3999 * @domain: the domain for the string
4000 * @sig: the signature of a metadata string
4002 * Returns: a MonoString for a string stored in the metadata
4005 mono_ldstr_metdata_sig (MonoDomain *domain, const char* sig)
4007 const char *str = sig;
4008 MonoString *o, *interned;
4011 len2 = mono_metadata_decode_blob_size (str, &str);
4014 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
4015 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
4018 guint16 *p2 = (guint16*)mono_string_chars (o);
4019 for (i = 0; i < len2; ++i) {
4020 *p2 = GUINT16_FROM_LE (*p2);
4026 if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
4028 /* o will get garbage collected */
4032 o = mono_string_get_pinned (o);
4033 mono_g_hash_table_insert (domain->ldstr_table, o, o);
4040 * mono_string_to_utf8:
4041 * @s: a System.String
4043 * Return the UTF8 representation for @s.
4044 * the resulting buffer nedds to be freed with g_free().
4047 mono_string_to_utf8 (MonoString *s)
4050 GError *error = NULL;
4056 return g_strdup ("");
4058 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, NULL, &error);
4060 MonoException *exc = mono_get_exception_argument ("string", error->message);
4061 g_error_free (error);
4062 mono_raise_exception(exc);
4069 * mono_string_to_utf16:
4072 * Return an null-terminated array of the utf-16 chars
4073 * contained in @s. The result must be freed with g_free().
4074 * This is a temporary helper until our string implementation
4075 * is reworked to always include the null terminating char.
4078 mono_string_to_utf16 (MonoString *s)
4085 as = g_malloc ((s->length * 2) + 2);
4086 as [(s->length * 2)] = '\0';
4087 as [(s->length * 2) + 1] = '\0';
4090 return (gunichar2 *)(as);
4093 memcpy (as, mono_string_chars(s), s->length * 2);
4094 return (gunichar2 *)(as);
4098 * mono_string_from_utf16:
4099 * @data: the UTF16 string (LPWSTR) to convert
4101 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
4103 * Returns: a MonoString.
4106 mono_string_from_utf16 (gunichar2 *data)
4108 MonoDomain *domain = mono_domain_get ();
4114 while (data [len]) len++;
4116 return mono_string_new_utf16 (domain, data, len);
4120 * mono_string_to_utf8_mp:
4121 * @s: a System.String
4123 * Same as mono_string_to_utf8, but allocate the string from a mempool.
4126 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s)
4128 char *r = mono_string_to_utf8 (s);
4135 len = strlen (r) + 1;
4136 mp_s = mono_mempool_alloc (mp, len);
4137 memcpy (mp_s, r, len);
4145 default_ex_handler (MonoException *ex)
4147 MonoObject *o = (MonoObject*)ex;
4148 g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
4152 static MonoExceptionFunc ex_handler = default_ex_handler;
4155 * mono_install_handler:
4156 * @func: exception handler
4158 * This is an internal JIT routine used to install the handler for exceptions
4162 mono_install_handler (MonoExceptionFunc func)
4164 ex_handler = func? func: default_ex_handler;
4168 * mono_raise_exception:
4169 * @ex: exception object
4171 * Signal the runtime that the exception @ex has been raised in unmanaged code.
4174 mono_raise_exception (MonoException *ex)
4177 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
4178 * that will cause gcc to omit the function epilog, causing problems when
4179 * the JIT tries to walk the stack, since the return address on the stack
4180 * will point into the next function in the executable, not this one.
4183 if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class)
4184 MONO_OBJECT_SETREF (mono_thread_current (), abort_exc, ex);
4190 * mono_wait_handle_new:
4191 * @domain: Domain where the object will be created
4192 * @handle: Handle for the wait handle
4194 * Returns: A new MonoWaitHandle created in the given domain for the given handle
4197 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
4199 MonoWaitHandle *res;
4200 gpointer params [1];
4201 static MonoMethod *handle_set;
4203 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.waithandle_class);
4205 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
4207 handle_set = mono_class_get_property_from_name (mono_defaults.waithandle_class, "Handle")->set;
4209 params [0] = &handle;
4210 mono_runtime_invoke (handle_set, res, params, NULL);
4216 mono_wait_handle_get_handle (MonoWaitHandle *handle)
4218 static MonoClassField *f_os_handle;
4219 static MonoClassField *f_safe_handle;
4221 if (!f_os_handle && !f_safe_handle) {
4222 f_os_handle = mono_class_get_field_from_name (mono_defaults.waithandle_class, "os_handle");
4223 f_safe_handle = mono_class_get_field_from_name (mono_defaults.waithandle_class, "safe_wait_handle");
4228 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
4232 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
4238 * mono_async_result_new:
4239 * @domain:domain where the object will be created.
4240 * @handle: wait handle.
4241 * @state: state to pass to AsyncResult
4242 * @data: C closure data.
4244 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
4245 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
4249 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
4251 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
4252 MonoMethod *method = mono_get_context_capture_method ();
4254 /* we must capture the execution context from the original thread */
4256 MONO_OBJECT_SETREF (res, execution_context, mono_runtime_invoke (method, NULL, NULL, NULL));
4257 /* note: result may be null if the flow is suppressed */
4261 MONO_OBJECT_SETREF (res, object_data, object_data);
4262 MONO_OBJECT_SETREF (res, async_state, state);
4264 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
4266 res->sync_completed = FALSE;
4267 res->completed = FALSE;
4273 mono_message_init (MonoDomain *domain,
4274 MonoMethodMessage *this,
4275 MonoReflectionMethod *method,
4276 MonoArray *out_args)
4278 MonoMethodSignature *sig = mono_method_signature (method->method);
4284 MONO_OBJECT_SETREF (this, method, method);
4286 MONO_OBJECT_SETREF (this, args, mono_array_new (domain, mono_defaults.object_class, sig->param_count));
4287 MONO_OBJECT_SETREF (this, arg_types, mono_array_new (domain, mono_defaults.byte_class, sig->param_count));
4288 this->async_result = NULL;
4289 this->call_type = CallType_Sync;
4291 names = g_new (char *, sig->param_count);
4292 mono_method_get_param_names (method->method, (const char **) names);
4293 MONO_OBJECT_SETREF (this, names, mono_array_new (domain, mono_defaults.string_class, sig->param_count));
4295 for (i = 0; i < sig->param_count; i++) {
4296 name = mono_string_new (domain, names [i]);
4297 mono_array_setref (this->names, i, name);
4301 for (i = 0, j = 0; i < sig->param_count; i++) {
4303 if (sig->params [i]->byref) {
4305 MonoObject* arg = mono_array_get (out_args, gpointer, j);
4306 mono_array_setref (this->args, i, arg);
4310 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
4314 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
4317 mono_array_set (this->arg_types, guint8, i, arg_type);
4322 * mono_remoting_invoke:
4323 * @real_proxy: pointer to a RealProxy object
4324 * @msg: The MonoMethodMessage to execute
4325 * @exc: used to store exceptions
4326 * @out_args: used to store output arguments
4328 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
4329 * IMessage interface and it is not trivial to extract results from there. So
4330 * we call an helper method PrivateInvoke instead of calling
4331 * RealProxy::Invoke() directly.
4333 * Returns: the result object.
4336 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
4337 MonoObject **exc, MonoArray **out_args)
4339 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
4342 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
4345 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
4347 real_proxy->vtable->domain->private_invoke_method = im;
4350 pa [0] = real_proxy;
4355 return mono_runtime_invoke (im, NULL, pa, exc);
4359 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
4360 MonoObject **exc, MonoArray **out_args)
4364 MonoMethodSignature *sig;
4366 int i, j, outarg_count = 0;
4368 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
4370 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
4371 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
4372 target = tp->rp->unwrapped_server;
4374 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
4378 domain = mono_domain_get ();
4379 method = msg->method->method;
4380 sig = mono_method_signature (method);
4382 for (i = 0; i < sig->param_count; i++) {
4383 if (sig->params [i]->byref)
4387 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
4388 *out_args = mono_array_new (domain, mono_defaults.object_class, outarg_count);
4391 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
4393 for (i = 0, j = 0; i < sig->param_count; i++) {
4394 if (sig->params [i]->byref) {
4396 arg = mono_array_get (msg->args, gpointer, i);
4397 mono_array_setref (*out_args, j, arg);
4406 * mono_print_unhandled_exception:
4407 * @exc: The exception
4409 * Prints the unhandled exception.
4412 mono_print_unhandled_exception (MonoObject *exc)
4414 char *message = (char *) "";
4418 gboolean free_message = FALSE;
4420 if (mono_object_isinst (exc, mono_defaults.exception_class)) {
4421 klass = exc->vtable->klass;
4423 while (klass && method == NULL) {
4424 method = mono_class_get_method_from_name_flags (klass, "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
4426 klass = klass->parent;
4431 str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL);
4433 message = mono_string_to_utf8 (str);
4434 free_message = TRUE;
4439 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
4440 * exc->vtable->klass->name, message);
4442 g_printerr ("\nUnhandled Exception: %s\n", message);
4449 * mono_delegate_ctor:
4450 * @this: pointer to an uninitialized delegate object
4451 * @target: target object
4452 * @addr: pointer to native code
4454 * This is used to initialize a delegate. We also insert the method_info if
4455 * we find the info with mono_jit_info_table_find().
4458 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
4460 MonoDomain *domain = mono_domain_get ();
4461 MonoDelegate *delegate = (MonoDelegate *)this;
4462 MonoMethod *method = NULL;
4469 class = this->vtable->klass;
4471 if ((ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr)))) {
4472 method = ji->method;
4473 MONO_OBJECT_SETREF (delegate, method_info, mono_method_get_object (domain, method, NULL));
4476 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
4478 method = mono_marshal_get_remoting_invoke (method);
4479 delegate->method_ptr = mono_compile_method (method);
4480 MONO_OBJECT_SETREF (delegate, target, target);
4481 } else if (mono_method_signature (method)->hasthis && method->klass->valuetype) {
4482 method = mono_marshal_get_unbox_wrapper (method);
4483 delegate->method_ptr = mono_compile_method (method);
4484 MONO_OBJECT_SETREF (delegate, target, target);
4486 delegate->method_ptr = addr;
4487 MONO_OBJECT_SETREF (delegate, target, target);
4490 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->klass);
4494 * mono_method_call_message_new:
4495 * @method: method to encapsulate
4496 * @params: parameters to the method
4497 * @invoke: optional, delegate invoke.
4498 * @cb: async callback delegate.
4499 * @state: state passed to the async callback.
4501 * Translates arguments pointers into a MonoMethodMessage.
4504 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
4505 MonoDelegate **cb, MonoObject **state)
4507 MonoDomain *domain = mono_domain_get ();
4508 MonoMethodSignature *sig = mono_method_signature (method);
4509 MonoMethodMessage *msg;
4512 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
4515 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
4516 count = sig->param_count - 2;
4518 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
4519 count = sig->param_count;
4522 for (i = 0; i < count; i++) {
4527 if (sig->params [i]->byref)
4528 vpos = *((gpointer *)params [i]);
4532 type = sig->params [i]->type;
4533 class = mono_class_from_mono_type (sig->params [i]);
4535 if (class->valuetype)
4536 arg = mono_value_box (domain, class, vpos);
4538 arg = *((MonoObject **)vpos);
4540 mono_array_setref (msg->args, i, arg);
4543 if (cb != NULL && state != NULL) {
4544 *cb = *((MonoDelegate **)params [i]);
4546 *state = *((MonoObject **)params [i]);
4553 * mono_method_return_message_restore:
4555 * Restore results from message based processing back to arguments pointers
4558 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
4560 MonoMethodSignature *sig = mono_method_signature (method);
4561 int i, j, type, size, out_len;
4563 if (out_args == NULL)
4565 out_len = mono_array_length (out_args);
4569 for (i = 0, j = 0; i < sig->param_count; i++) {
4570 MonoType *pt = sig->params [i];
4575 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
4577 arg = mono_array_get (out_args, gpointer, j);
4581 case MONO_TYPE_VOID:
4582 g_assert_not_reached ();
4586 case MONO_TYPE_BOOLEAN:
4589 case MONO_TYPE_CHAR:
4596 case MONO_TYPE_VALUETYPE: {
4598 size = mono_class_value_size (((MonoObject*)arg)->vtable->klass, NULL);
4599 memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
4602 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
4603 memset (*((gpointer *)params [i]), 0, size);
4607 case MONO_TYPE_STRING:
4608 case MONO_TYPE_CLASS:
4609 case MONO_TYPE_ARRAY:
4610 case MONO_TYPE_SZARRAY:
4611 case MONO_TYPE_OBJECT:
4612 **((MonoObject ***)params [i]) = (MonoObject *)arg;
4615 g_assert_not_reached ();
4624 * mono_load_remote_field:
4625 * @this: pointer to an object
4626 * @klass: klass of the object containing @field
4627 * @field: the field to load
4628 * @res: a storage to store the result
4630 * This method is called by the runtime on attempts to load fields of
4631 * transparent proxy objects. @this points to such TP, @klass is the class of
4632 * the object containing @field. @res is a storage location which can be
4633 * used to store the result.
4635 * Returns: an address pointing to the value of field.
4638 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
4640 static MonoMethod *getter = NULL;
4641 MonoDomain *domain = mono_domain_get ();
4642 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
4643 MonoClass *field_class;
4644 MonoMethodMessage *msg;
4645 MonoArray *out_args;
4649 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
4650 g_assert (res != NULL);
4652 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
4653 mono_field_get_value (tp->rp->unwrapped_server, field, res);
4658 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
4662 field_class = mono_class_from_mono_type (field->type);
4664 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
4665 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
4666 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
4668 full_name = mono_type_get_full_name (klass);
4669 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
4670 mono_array_setref (msg->args, 1, mono_string_new (domain, field->name));
4673 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
4675 if (exc) mono_raise_exception ((MonoException *)exc);
4677 if (mono_array_length (out_args) == 0)
4680 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
4682 if (field_class->valuetype) {
4683 return ((char *)*res) + sizeof (MonoObject);
4689 * mono_load_remote_field_new:
4694 * Missing documentation.
4697 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
4699 static MonoMethod *getter = NULL;
4700 MonoDomain *domain = mono_domain_get ();
4701 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
4702 MonoClass *field_class;
4703 MonoMethodMessage *msg;
4704 MonoArray *out_args;
4705 MonoObject *exc, *res;
4708 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
4710 field_class = mono_class_from_mono_type (field->type);
4712 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
4714 if (field_class->valuetype) {
4715 res = mono_object_new (domain, field_class);
4716 val = ((gchar *) res) + sizeof (MonoObject);
4720 mono_field_get_value (tp->rp->unwrapped_server, field, val);
4725 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
4729 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
4730 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
4732 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
4734 full_name = mono_type_get_full_name (klass);
4735 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
4736 mono_array_setref (msg->args, 1, mono_string_new (domain, field->name));
4739 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
4741 if (exc) mono_raise_exception ((MonoException *)exc);
4743 if (mono_array_length (out_args) == 0)
4746 res = mono_array_get (out_args, MonoObject *, 0);
4752 * mono_store_remote_field:
4753 * @this: pointer to an object
4754 * @klass: klass of the object containing @field
4755 * @field: the field to load
4756 * @val: the value/object to store
4758 * This method is called by the runtime on attempts to store fields of
4759 * transparent proxy objects. @this points to such TP, @klass is the class of
4760 * the object containing @field. @val is the new value to store in @field.
4763 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
4765 static MonoMethod *setter = NULL;
4766 MonoDomain *domain = mono_domain_get ();
4767 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
4768 MonoClass *field_class;
4769 MonoMethodMessage *msg;
4770 MonoArray *out_args;
4775 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
4777 field_class = mono_class_from_mono_type (field->type);
4779 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
4780 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
4781 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
4786 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
4790 if (field_class->valuetype)
4791 arg = mono_value_box (domain, field_class, val);
4793 arg = *((MonoObject **)val);
4796 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
4797 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
4799 full_name = mono_type_get_full_name (klass);
4800 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
4801 mono_array_setref (msg->args, 1, mono_string_new (domain, field->name));
4802 mono_array_setref (msg->args, 2, arg);
4805 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
4807 if (exc) mono_raise_exception ((MonoException *)exc);
4811 * mono_store_remote_field_new:
4817 * Missing documentation
4820 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
4822 static MonoMethod *setter = NULL;
4823 MonoDomain *domain = mono_domain_get ();
4824 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
4825 MonoClass *field_class;
4826 MonoMethodMessage *msg;
4827 MonoArray *out_args;
4831 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
4833 field_class = mono_class_from_mono_type (field->type);
4835 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
4836 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
4837 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
4842 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
4846 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
4847 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
4849 full_name = mono_type_get_full_name (klass);
4850 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
4851 mono_array_setref (msg->args, 1, mono_string_new (domain, field->name));
4852 mono_array_setref (msg->args, 2, arg);
4855 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
4857 if (exc) mono_raise_exception ((MonoException *)exc);
4861 * mono_get_addr_from_ftnptr:
4863 * Given a pointer to a function descriptor, return the function address.
4864 * This is only needed on IA64.
4867 mono_get_addr_from_ftnptr (gpointer descr)
4870 return *(gpointer*)descr;
4878 * mono_string_chars:
4881 * Returns a pointer to the UCS16 characters stored in the MonoString
4884 mono_string_chars(MonoString *s)
4886 /* This method is here only for documentation extraction, this is a macro */
4890 * mono_string_length:
4893 * Returns the lenght in characters of the string
4896 mono_string_length (MonoString *s)
4898 /* This method is here only for documentation extraction, this is a macro */