2 * object.c: Object creation for the Mono runtime
5 * Miguel de Icaza (miguel@ximian.com)
6 * Paolo Molaro (lupus@ximian.com)
8 * (C) 2001-2004 Ximian, Inc.
15 #include <mono/metadata/mono-endian.h>
16 #include <mono/metadata/tabledefs.h>
17 #include <mono/metadata/tokentype.h>
18 #include <mono/metadata/loader.h>
19 #include <mono/metadata/object.h>
20 #include <mono/metadata/gc-internal.h>
21 #include <mono/metadata/exception.h>
22 #include <mono/metadata/domain-internals.h>
23 #include "mono/metadata/metadata-internals.h"
24 #include "mono/metadata/class-internals.h"
25 #include <mono/metadata/assembly.h>
26 #include <mono/metadata/threadpool.h>
27 #include <mono/metadata/marshal.h>
28 #include "mono/metadata/debug-helpers.h"
29 #include "mono/metadata/marshal.h"
30 #include <mono/metadata/threads.h>
31 #include <mono/metadata/threads-types.h>
32 #include <mono/metadata/environment.h>
33 #include "mono/metadata/profiler-private.h"
34 #include "mono/metadata/security-manager.h"
35 #include "mono/metadata/mono-debug-debugger.h"
36 #include <mono/metadata/gc-internal.h>
37 #include <mono/utils/strenc.h>
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 GC_NO_DESCRIPTOR ((gpointer)(0 | GC_DS_LENGTH))
45 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_GCJ_MALLOC ((size),(type)); } while (0)
47 #define GC_NO_DESCRIPTOR (NULL)
48 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_MALLOC ((size)); *(gpointer*)dest = (type);} while (0)
52 #define GC_NO_DESCRIPTOR (NULL)
53 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
54 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
55 #define ALLOC_TYPED(dest,size,type) do { (dest) = mono_gc_alloc_obj (type, size);} while (0)
57 #define NEED_TO_ZERO_PTRFREE 1
58 #define GC_NO_DESCRIPTOR (NULL)
59 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = malloc ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
60 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = calloc (1, (size)); (obj)->vtable = (vt);} while (0)
61 #define ALLOC_TYPED(dest,size,type) do { (dest) = calloc (1, (size)); *(gpointer*)dest = (type);} while (0)
65 static MonoObject* mono_object_new_ptrfree (MonoVTable *vtable);
66 static MonoObject* mono_object_new_ptrfree_box (MonoVTable *vtable);
69 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value);
72 mono_ldstr_metdata_sig (MonoDomain *domain, const char* sig);
74 #define ldstr_lock() EnterCriticalSection (&ldstr_section)
75 #define ldstr_unlock() LeaveCriticalSection (&ldstr_section)
76 static CRITICAL_SECTION ldstr_section;
78 static gboolean profile_allocs = TRUE;
81 mono_runtime_object_init (MonoObject *this)
83 MonoMethod *method = NULL;
84 MonoClass *klass = this->vtable->klass;
86 method = mono_class_get_method_from_name (klass, ".ctor", 0);
89 if (method->klass->valuetype)
90 this = mono_object_unbox (this);
91 mono_runtime_invoke (method, this, NULL, NULL);
94 /* The pseudo algorithm for type initialization from the spec
95 Note it doesn't say anything about domains - only threads.
97 2. If the type is initialized you are done.
98 2.1. If the type is not yet initialized, try to take an
100 2.2. If successful, record this thread as responsible for
101 initializing the type and proceed to step 2.3.
102 2.2.1. If not, see whether this thread or any thread
103 waiting for this thread to complete already holds the lock.
104 2.2.2. If so, return since blocking would create a deadlock. This thread
105 will now see an incompletely initialized state for the type,
106 but no deadlock will arise.
107 2.2.3 If not, block until the type is initialized then return.
108 2.3 Initialize the parent type and then all interfaces implemented
110 2.4 Execute the type initialization code for this type.
111 2.5 Mark the type as initialized, release the initialization lock,
112 awaken any threads waiting for this type to be initialized,
119 guint32 initializing_tid;
120 guint32 waiting_count;
122 CRITICAL_SECTION initialization_section;
123 } TypeInitializationLock;
125 /* for locking access to type_initialization_hash and blocked_thread_hash */
126 #define mono_type_initialization_lock() EnterCriticalSection (&type_initialization_section)
127 #define mono_type_initialization_unlock() LeaveCriticalSection (&type_initialization_section)
128 static CRITICAL_SECTION type_initialization_section;
130 /* from vtable to lock */
131 static GHashTable *type_initialization_hash;
133 /* from thread id to thread id being waited on */
134 static GHashTable *blocked_thread_hash;
137 static MonoThread *main_thread;
140 * mono_thread_set_main:
141 * @thread: thread to set as the main thread
143 * This function can be used to instruct the runtime to treat @thread
144 * as the main thread, ie, the thread that would normally execute the Main()
145 * method. This basically means that at the end of @thread, the runtime will
146 * wait for the existing foreground threads to quit and other such details.
149 mono_thread_set_main (MonoThread *thread)
151 main_thread = thread;
155 mono_thread_get_main (void)
161 mono_type_initialization_init (void)
163 InitializeCriticalSection (&type_initialization_section);
164 type_initialization_hash = g_hash_table_new (NULL, NULL);
165 blocked_thread_hash = g_hash_table_new (NULL, NULL);
166 InitializeCriticalSection (&ldstr_section);
170 mono_type_initialization_cleanup (void)
173 /* This is causing race conditions with
174 * mono_release_type_locks
176 DeleteCriticalSection (&type_initialization_section);
178 DeleteCriticalSection (&ldstr_section);
182 * get_type_init_exception_for_vtable:
184 * Return the stored type initialization exception for VTABLE.
186 static MonoException*
187 get_type_init_exception_for_vtable (MonoVTable *vtable)
189 MonoDomain *domain = vtable->domain;
190 MonoClass *klass = vtable->klass;
194 g_assert (vtable->init_failed);
197 * If the initializing thread was rudely aborted, the exception is not stored
201 mono_domain_lock (domain);
202 if (domain->type_init_exception_hash)
203 ex = mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
204 mono_domain_unlock (domain);
207 if (klass->name_space && *klass->name_space)
208 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
210 full_name = g_strdup (klass->name);
211 ex = mono_get_exception_type_initialization (full_name, NULL);
218 * mono_runtime_class_init:
219 * @vtable: vtable that needs to be initialized
221 * This routine calls the class constructor for @vtable.
224 mono_runtime_class_init (MonoVTable *vtable)
226 mono_runtime_class_init_full (vtable, TRUE);
230 * mono_runtime_class_init_full:
231 * @vtable that neeeds to be initialized
232 * @raise_exception is TRUE, exceptions are raised intead of returned
236 mono_runtime_class_init_full (MonoVTable *vtable, gboolean raise_exception)
239 MonoException *exc_to_throw;
240 MonoMethod *method = NULL;
246 if (vtable->initialized)
250 klass = vtable->klass;
252 if (!klass->image->checked_module_cctor) {
253 mono_image_check_for_module_cctor (klass->image);
254 if (klass->image->has_module_cctor) {
255 MonoClass *module_klass = mono_class_get (klass->image, MONO_TOKEN_TYPE_DEF | 1);
256 mono_runtime_class_init (mono_class_vtable (vtable->domain, module_klass));
259 method = mono_class_get_cctor (klass);
262 MonoDomain *domain = vtable->domain;
263 TypeInitializationLock *lock;
264 guint32 tid = GetCurrentThreadId();
265 int do_initialization = 0;
266 MonoDomain *last_domain = NULL;
268 mono_type_initialization_lock ();
269 /* double check... */
270 if (vtable->initialized) {
271 mono_type_initialization_unlock ();
274 if (vtable->init_failed) {
275 mono_type_initialization_unlock ();
277 /* The type initialization already failed once, rethrow the same exception */
279 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
280 return get_type_init_exception_for_vtable (vtable);
282 lock = g_hash_table_lookup (type_initialization_hash, vtable);
284 /* This thread will get to do the initialization */
285 if (mono_domain_get () != domain) {
286 /* Transfer into the target domain */
287 last_domain = mono_domain_get ();
288 if (!mono_domain_set (domain, FALSE)) {
289 vtable->initialized = 1;
290 mono_type_initialization_unlock ();
292 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
293 return mono_get_exception_appdomain_unloaded ();
296 lock = g_malloc (sizeof(TypeInitializationLock));
297 InitializeCriticalSection (&lock->initialization_section);
298 lock->initializing_tid = tid;
299 lock->waiting_count = 1;
301 /* grab the vtable lock while this thread still owns type_initialization_section */
302 EnterCriticalSection (&lock->initialization_section);
303 g_hash_table_insert (type_initialization_hash, vtable, lock);
304 do_initialization = 1;
307 TypeInitializationLock *pending_lock;
309 if (lock->initializing_tid == tid || lock->done) {
310 mono_type_initialization_unlock ();
313 /* see if the thread doing the initialization is already blocked on this thread */
314 blocked = GUINT_TO_POINTER (lock->initializing_tid);
315 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
316 if (pending_lock->initializing_tid == tid) {
317 if (!pending_lock->done) {
318 mono_type_initialization_unlock ();
321 /* the thread doing the initialization is blocked on this thread,
322 but on a lock that has already been freed. It just hasn't got
327 blocked = GUINT_TO_POINTER (pending_lock->initializing_tid);
329 ++lock->waiting_count;
330 /* record the fact that we are waiting on the initializing thread */
331 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
333 mono_type_initialization_unlock ();
335 if (do_initialization) {
336 mono_runtime_invoke (method, NULL, NULL, (MonoObject **) &exc);
338 /* If the initialization failed, mark the class as unusable. */
339 /* Avoid infinite loops */
341 (klass->image == mono_defaults.corlib &&
342 !strcmp (klass->name_space, "System") &&
343 !strcmp (klass->name, "TypeInitializationException")))) {
344 vtable->init_failed = 1;
346 if (klass->name_space && *klass->name_space)
347 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
349 full_name = g_strdup (klass->name);
350 exc_to_throw = mono_get_exception_type_initialization (full_name, exc);
354 * Store the exception object so it could be thrown on subsequent
357 mono_domain_lock (domain);
358 if (!domain->type_init_exception_hash)
359 domain->type_init_exception_hash = mono_g_hash_table_new_type (mono_aligned_addr_hash, NULL, MONO_HASH_VALUE_GC);
360 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
361 mono_domain_unlock (domain);
365 mono_domain_set (last_domain, TRUE);
367 LeaveCriticalSection (&lock->initialization_section);
369 /* this just blocks until the initializing thread is done */
370 EnterCriticalSection (&lock->initialization_section);
371 LeaveCriticalSection (&lock->initialization_section);
374 mono_type_initialization_lock ();
375 if (lock->initializing_tid != tid)
376 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
377 --lock->waiting_count;
378 if (lock->waiting_count == 0) {
379 DeleteCriticalSection (&lock->initialization_section);
380 g_hash_table_remove (type_initialization_hash, vtable);
383 if (!vtable->init_failed)
384 vtable->initialized = 1;
385 mono_type_initialization_unlock ();
387 if (vtable->init_failed) {
388 /* Either we were the initializing thread or we waited for the initialization */
390 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
391 return get_type_init_exception_for_vtable (vtable);
394 vtable->initialized = 1;
401 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
403 MonoVTable *vtable = (MonoVTable*)key;
405 TypeInitializationLock *lock = (TypeInitializationLock*) value;
406 if (lock->initializing_tid == GPOINTER_TO_UINT (user) && !lock->done) {
409 * Have to set this since it cannot be set by the normal code in
410 * mono_runtime_class_init (). In this case, the exception object is not stored,
411 * and get_type_init_exception_for_class () needs to be aware of this.
413 vtable->init_failed = 1;
414 LeaveCriticalSection (&lock->initialization_section);
415 --lock->waiting_count;
416 if (lock->waiting_count == 0) {
417 DeleteCriticalSection (&lock->initialization_section);
426 mono_release_type_locks (MonoThread *thread)
428 mono_type_initialization_lock ();
429 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, (gpointer)(gsize)(thread->tid));
430 mono_type_initialization_unlock ();
434 default_trampoline (MonoMethod *method)
440 default_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
442 g_assert_not_reached ();
448 default_remoting_trampoline (MonoMethod *method, MonoRemotingTarget target)
450 g_error ("remoting not installed");
455 default_delegate_trampoline (MonoClass *klass)
457 g_assert_not_reached ();
461 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
462 static MonoJumpTrampoline arch_create_jump_trampoline = default_jump_trampoline;
463 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
464 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
465 static MonoImtThunkBuilder imt_thunk_builder = NULL;
466 #define ARCH_USE_IMT (imt_thunk_builder != NULL)
467 #if (MONO_IMT_SIZE > 32)
468 #error "MONO_IMT_SIZE cannot be larger than 32"
472 mono_install_trampoline (MonoTrampoline func)
474 arch_create_jit_trampoline = func? func: default_trampoline;
478 mono_install_jump_trampoline (MonoJumpTrampoline func)
480 arch_create_jump_trampoline = func? func: default_jump_trampoline;
484 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
486 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
490 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
492 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
496 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
497 imt_thunk_builder = func;
500 static MonoCompileFunc default_mono_compile_method = NULL;
503 * mono_install_compile_method:
504 * @func: function to install
506 * This is a VM internal routine
509 mono_install_compile_method (MonoCompileFunc func)
511 default_mono_compile_method = func;
515 * mono_compile_method:
516 * @method: The method to compile.
518 * This JIT-compiles the method, and returns the pointer to the native code
522 mono_compile_method (MonoMethod *method)
524 if (!default_mono_compile_method) {
525 g_error ("compile method called on uninitialized runtime");
528 return default_mono_compile_method (method);
532 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
534 return arch_create_jump_trampoline (domain, method, add_sync_wrapper);
538 mono_runtime_create_delegate_trampoline (MonoClass *klass)
540 return arch_create_delegate_trampoline (klass);
543 static MonoFreeMethodFunc default_mono_free_method = NULL;
546 * mono_install_free_method:
547 * @func: pointer to the MonoFreeMethodFunc used to release a method
549 * This is an internal VM routine, it is used for the engines to
550 * register a handler to release the resources associated with a method.
552 * Methods are freed when no more references to the delegate that holds
556 mono_install_free_method (MonoFreeMethodFunc func)
558 default_mono_free_method = func;
562 * mono_runtime_free_method:
563 * @domain; domain where the method is hosted
564 * @method: method to release
566 * This routine is invoked to free the resources associated with
567 * a method that has been JIT compiled. This is used to discard
568 * methods that were used only temporarily (for example, used in marshalling)
572 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
574 if (default_mono_free_method != NULL)
575 default_mono_free_method (domain, method);
577 mono_free_method (method);
581 * The vtables in the root appdomain are assumed to be reachable by other
582 * roots, and we don't use typed allocation in the other domains.
585 /* The sync block is no longer a GC pointer */
586 #define GC_HEADER_BITMAP (0)
588 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
591 compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
593 MonoClassField *field;
599 max_size = mono_class_data_size (class) / sizeof (gpointer);
601 max_size = class->instance_size / sizeof (gpointer);
602 if (max_size >= size) {
603 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
606 for (p = class; p != NULL; p = p->parent) {
607 gpointer iter = NULL;
608 while ((field = mono_class_get_fields (p, &iter))) {
612 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
614 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
617 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
620 /* FIXME: should not happen, flag as type load error */
621 if (field->type->byref)
624 pos = field->offset / sizeof (gpointer);
627 type = mono_type_get_underlying_type (field->type);
628 switch (type->type) {
631 case MONO_TYPE_FNPTR:
633 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
638 if (class->image != mono_defaults.corlib)
641 case MONO_TYPE_STRING:
642 case MONO_TYPE_SZARRAY:
643 case MONO_TYPE_CLASS:
644 case MONO_TYPE_OBJECT:
645 case MONO_TYPE_ARRAY:
646 g_assert ((field->offset % sizeof(gpointer)) == 0);
648 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
649 *max_set = MAX (*max_set, pos);
651 case MONO_TYPE_GENERICINST:
652 if (!mono_type_generic_inst_is_valuetype (type)) {
653 g_assert ((field->offset % sizeof(gpointer)) == 0);
655 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
656 *max_set = MAX (*max_set, pos);
661 case MONO_TYPE_VALUETYPE: {
662 MonoClass *fclass = mono_class_from_mono_type (field->type);
663 if (fclass->has_references) {
664 /* remove the object header */
665 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
679 case MONO_TYPE_BOOLEAN:
683 g_assert_not_reached ();
695 * similar to the above, but sets the bits in the bitmap for any non-ref field
696 * and ignores static fields
699 compute_class_non_ref_bitmap (MonoClass *class, gsize *bitmap, int size, int offset)
701 MonoClassField *field;
706 max_size = class->instance_size / sizeof (gpointer);
707 if (max_size >= size) {
708 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
711 for (p = class; p != NULL; p = p->parent) {
712 gpointer iter = NULL;
713 while ((field = mono_class_get_fields (p, &iter))) {
716 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
718 /* FIXME: should not happen, flag as type load error */
719 if (field->type->byref)
722 pos = field->offset / sizeof (gpointer);
725 type = mono_type_get_underlying_type (field->type);
726 switch (type->type) {
727 #if SIZEOF_VOID_P == 8
731 case MONO_TYPE_FNPTR:
736 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
737 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
738 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
741 #if SIZEOF_VOID_P == 4
745 case MONO_TYPE_FNPTR:
750 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
751 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
752 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
758 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
759 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
760 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
763 case MONO_TYPE_BOOLEAN:
766 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
768 case MONO_TYPE_STRING:
769 case MONO_TYPE_SZARRAY:
770 case MONO_TYPE_CLASS:
771 case MONO_TYPE_OBJECT:
772 case MONO_TYPE_ARRAY:
774 case MONO_TYPE_GENERICINST:
775 if (!mono_type_generic_inst_is_valuetype (type)) {
780 case MONO_TYPE_VALUETYPE: {
781 MonoClass *fclass = mono_class_from_mono_type (field->type);
782 /* remove the object header */
783 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
787 g_assert_not_reached ();
796 * mono_class_insecure_overlapping:
797 * check if a class with explicit layout has references and non-references
798 * fields overlapping.
800 * Returns: TRUE if it is insecure to load the type.
803 mono_class_insecure_overlapping (MonoClass *klass)
807 gsize default_bitmap [4] = {0};
809 gsize default_nrbitmap [4] = {0};
810 int i, insecure = FALSE;
813 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
814 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
816 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
817 int idx = i % (sizeof (bitmap [0]) * 8);
818 if (bitmap [idx] & nrbitmap [idx]) {
823 if (bitmap != default_bitmap)
825 if (nrbitmap != default_nrbitmap)
828 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
836 mono_string_alloc (int length)
838 return mono_string_new_size (mono_domain_get (), length);
842 mono_class_compute_gc_descriptor (MonoClass *class)
846 gsize default_bitmap [4] = {0};
847 static gboolean gcj_inited = FALSE;
852 mono_register_jit_icall (mono_object_new_ptrfree, "mono_object_new_ptrfree", mono_create_icall_signature ("object ptr"), FALSE);
853 mono_register_jit_icall (mono_object_new_ptrfree_box, "mono_object_new_ptrfree_box", mono_create_icall_signature ("object ptr"), FALSE);
854 mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
855 mono_register_jit_icall (mono_string_alloc, "mono_string_alloc", mono_create_icall_signature ("object int"), FALSE);
857 #ifdef HAVE_GC_GCJ_MALLOC
859 * This is not needed unless the relevant code in mono_get_allocation_ftn () is
863 #ifdef GC_REDIRECT_TO_LOCAL
864 mono_register_jit_icall (GC_local_gcj_malloc, "GC_local_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
865 mono_register_jit_icall (GC_local_gcj_fast_malloc, "GC_local_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
867 mono_register_jit_icall (GC_gcj_malloc, "GC_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
868 mono_register_jit_icall (GC_gcj_fast_malloc, "GC_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
873 mono_loader_unlock ();
877 mono_class_init (class);
879 if (class->gc_descr_inited)
882 class->gc_descr_inited = TRUE;
883 class->gc_descr = GC_NO_DESCRIPTOR;
885 bitmap = default_bitmap;
886 if (class == mono_defaults.string_class) {
887 class->gc_descr = (gpointer)mono_gc_make_descr_for_string (bitmap, 2);
888 } else if (class->rank) {
889 mono_class_compute_gc_descriptor (class->element_class);
890 if (!class->element_class->valuetype) {
892 class->gc_descr = mono_gc_make_descr_for_array (TRUE, &abm, 1, sizeof (gpointer));
893 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
894 class->name_space, class->name);*/
896 /* remove the object header */
897 bitmap = compute_class_bitmap (class->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
898 class->gc_descr = mono_gc_make_descr_for_array (TRUE, bitmap, mono_array_element_size (class) / sizeof (gpointer), mono_array_element_size (class));
899 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
900 class->name_space, class->name);*/
901 if (bitmap != default_bitmap)
905 /*static int count = 0;
908 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
909 class->gc_descr = (gpointer)mono_gc_make_descr_for_object (bitmap, max_set + 1, class->instance_size);
911 if (class->gc_descr == GC_NO_DESCRIPTOR)
912 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
914 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
915 if (bitmap != default_bitmap)
921 * field_is_special_static:
922 * @fklass: The MonoClass to look up.
923 * @field: The MonoClassField describing the field.
925 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
926 * SPECIAL_STATIC_NONE otherwise.
929 field_is_special_static (MonoClass *fklass, MonoClassField *field)
931 MonoCustomAttrInfo *ainfo;
933 ainfo = mono_custom_attrs_from_field (fklass, field);
936 for (i = 0; i < ainfo->num_attrs; ++i) {
937 MonoClass *klass = ainfo->attrs [i].ctor->klass;
938 if (klass->image == mono_defaults.corlib) {
939 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
940 mono_custom_attrs_free (ainfo);
941 return SPECIAL_STATIC_THREAD;
943 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
944 mono_custom_attrs_free (ainfo);
945 return SPECIAL_STATIC_CONTEXT;
949 mono_custom_attrs_free (ainfo);
950 return SPECIAL_STATIC_NONE;
953 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
954 #define mix(a,b,c) { \
955 a -= c; a ^= rot(c, 4); c += b; \
956 b -= a; b ^= rot(a, 6); a += c; \
957 c -= b; c ^= rot(b, 8); b += a; \
958 a -= c; a ^= rot(c,16); c += b; \
959 b -= a; b ^= rot(a,19); a += c; \
960 c -= b; c ^= rot(b, 4); b += a; \
962 #define final(a,b,c) { \
963 c ^= b; c -= rot(b,14); \
964 a ^= c; a -= rot(c,11); \
965 b ^= a; b -= rot(a,25); \
966 c ^= b; c -= rot(b,16); \
967 a ^= c; a -= rot(c,4); \
968 b ^= a; b -= rot(a,14); \
969 c ^= b; c -= rot(b,24); \
973 mono_method_get_imt_slot (MonoMethod *method) {
974 MonoMethodSignature *sig;
976 guint32 *hashes_start, *hashes;
981 * We do this to simplify generic sharing. It will hurt
982 * performance in cases where a class implements two different
983 * instantiations of the same generic interface.
985 if (method->is_inflated)
986 method = ((MonoMethodInflated*)method)->declaring;
988 sig = mono_method_signature (method);
989 hashes_count = sig->param_count + 4;
990 hashes_start = malloc (hashes_count * sizeof (guint32));
991 hashes = hashes_start;
993 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
994 printf ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod\n",
995 method->klass->name_space, method->klass->name, method->name);
996 g_assert_not_reached ();
999 /* Initialize hashes */
1000 hashes [0] = g_str_hash (method->klass->name);
1001 hashes [1] = g_str_hash (method->klass->name_space);
1002 hashes [2] = g_str_hash (method->name);
1003 hashes [3] = mono_metadata_type_hash (sig->ret);
1004 for (i = 0; i < sig->param_count; i++) {
1005 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1008 /* Setup internal state */
1009 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1011 /* Handle most of the hashes */
1012 while (hashes_count > 3) {
1021 /* Handle the last 3 hashes (all the case statements fall through) */
1022 switch (hashes_count) {
1023 case 3 : c += hashes [2];
1024 case 2 : b += hashes [1];
1025 case 1 : a += hashes [0];
1027 case 0: /* nothing left to add */
1031 free (hashes_start);
1032 /* Report the result */
1033 return c % MONO_IMT_SIZE;
1042 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1043 guint32 imt_slot = mono_method_get_imt_slot (method);
1044 MonoImtBuilderEntry *entry;
1046 if (slot_num >= 0 && imt_slot != slot_num) {
1047 /* we build just a single imt slot and this is not it */
1051 entry = malloc (sizeof (MonoImtBuilderEntry));
1052 entry->method = method;
1053 entry->vtable_slot = vtable_slot;
1054 entry->next = imt_builder [imt_slot];
1055 if (imt_builder [imt_slot] != NULL) {
1056 entry->children = imt_builder [imt_slot]->children + 1;
1057 if (entry->children == 1) {
1058 mono_stats.imt_slots_with_collisions++;
1059 *imt_collisions_bitmap |= (1 << imt_slot);
1062 entry->children = 0;
1063 mono_stats.imt_used_slots++;
1065 imt_builder [imt_slot] = entry;
1067 printf ("Added IMT slot for method (%p) %s.%s.%s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1068 method, method->klass->name_space, method->klass->name,
1069 method->name, imt_slot, vtable_slot, entry->children);
1075 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1077 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1081 e->method->klass->name_space,
1082 e->method->klass->name,
1085 printf (" * %s: NULL\n", message);
1091 compare_imt_builder_entries (const void *p1, const void *p2) {
1092 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1093 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1095 return (e1->method < e2->method) ? -1 : ((e1->method > e2->method) ? 1 : 0);
1099 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1101 int count = end - start;
1102 int chunk_start = out_array->len;
1105 for (i = start; i < end; ++i) {
1106 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1107 item->method = sorted_array [i]->method;
1108 item->vtable_slot = sorted_array [i]->vtable_slot;
1109 item->is_equals = TRUE;
1111 item->check_target_idx = out_array->len + 1;
1113 item->check_target_idx = 0;
1114 g_ptr_array_add (out_array, item);
1117 int middle = start + count / 2;
1118 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1120 item->method = sorted_array [middle]->method;
1121 item->is_equals = FALSE;
1122 g_ptr_array_add (out_array, item);
1123 imt_emit_ir (sorted_array, start, middle, out_array);
1124 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1130 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1131 int number_of_entries = entries->children + 1;
1132 MonoImtBuilderEntry **sorted_array = malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1133 GPtrArray *result = g_ptr_array_new ();
1134 MonoImtBuilderEntry *current_entry;
1137 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1138 sorted_array [i] = current_entry;
1140 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1142 /*for (i = 0; i < number_of_entries; i++) {
1143 print_imt_entry (" sorted array:", sorted_array [i], i);
1146 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1148 free (sorted_array);
1153 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry) {
1154 if (imt_builder_entry != NULL) {
1155 if (imt_builder_entry->children == 0) {
1156 /* No collision, return the vtable slot contents */
1157 return vtable->vtable [imt_builder_entry->vtable_slot];
1159 /* Collision, build the thunk */
1160 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1163 result = imt_thunk_builder (vtable, domain, (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len);
1164 for (i = 0; i < imt_ir->len; ++i)
1165 g_free (g_ptr_array_index (imt_ir, i));
1166 g_ptr_array_free (imt_ir, TRUE);
1176 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num) {
1179 guint32 imt_collisions_bitmap = 0;
1180 MonoImtBuilderEntry **imt_builder = calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1181 int method_count = 0;
1182 gboolean record_method_count_for_max_collisions = FALSE;
1185 printf ("Building IMT for class %s.%s\n", klass->name_space, klass->name);
1187 for (i = 0; i < klass->interface_offsets_count; ++i) {
1188 MonoClass *iface = klass->interfaces_packed [i];
1189 int interface_offset = klass->interface_offsets_packed [i];
1190 int method_slot_in_interface;
1191 mono_class_setup_methods (iface);
1192 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1193 MonoMethod *method = iface->methods [method_slot_in_interface];
1194 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1197 if (extra_interfaces) {
1198 int interface_offset = klass->vtable_size;
1200 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1201 MonoClass* iface = list_item->data;
1202 int method_slot_in_interface;
1203 mono_class_setup_methods (iface);
1204 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1205 MonoMethod *method = iface->methods [method_slot_in_interface];
1206 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1208 interface_offset += iface->method.count;
1211 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1212 /* overwrite the imt slot only if we're building all the entries or if
1213 * we're uilding this specific one
1215 if (slot_num < 0 || i == slot_num)
1216 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i]);
1218 printf ("initialize_imt_slot[%d]: %p\n", i, imt [i]);
1220 if (imt_builder [i] != NULL) {
1221 int methods_in_slot = imt_builder [i]->children + 1;
1222 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1223 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1224 record_method_count_for_max_collisions = TRUE;
1226 method_count += methods_in_slot;
1230 mono_stats.imt_number_of_methods += method_count;
1231 if (record_method_count_for_max_collisions) {
1232 mono_stats.imt_method_count_when_max_collisions = method_count;
1235 for (i = 0; i < MONO_IMT_SIZE; i++) {
1236 MonoImtBuilderEntry* entry = imt_builder [i];
1237 while (entry != NULL) {
1238 MonoImtBuilderEntry* next = entry->next;
1244 /* we OR the bitmap since we may build just a single imt slot at a time */
1245 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1249 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1250 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1253 static gpointer imt_trampoline = NULL;
1256 mono_install_imt_trampoline (gpointer tramp_code)
1258 imt_trampoline = tramp_code;
1261 static gpointer vtable_trampoline = NULL;
1264 mono_install_vtable_trampoline (gpointer tramp_code)
1266 vtable_trampoline = tramp_code;
1270 * mono_vtable_build_imt_slot:
1271 * @vtable: virtual object table struct
1272 * @imt_slot: slot in the IMT table
1274 * Fill the given @imt_slot in the IMT table of @vtable with
1275 * a trampoline or a thunk for the case of collisions.
1276 * This is part of the internal mono API.
1279 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1281 gpointer *imt = (gpointer*)vtable;
1282 imt -= MONO_IMT_SIZE;
1283 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1285 /* no support for extra interfaces: the proxy objects will need
1286 * to build the complete IMT
1287 * Update and heck needs to ahppen inside the proper domain lock, as all
1288 * the changes made to a MonoVTable.
1290 mono_domain_lock (vtable->domain);
1291 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1292 if (imt [imt_slot] == imt_trampoline)
1293 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1294 mono_domain_unlock (vtable->domain);
1297 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class);
1300 * mono_class_vtable:
1301 * @domain: the application domain
1302 * @class: the class to initialize
1304 * VTables are domain specific because we create domain specific code, and
1305 * they contain the domain specific static class data.
1306 * On failure, NULL is returned, and class->exception_type is set.
1309 mono_class_vtable (MonoDomain *domain, MonoClass *class)
1311 MonoClassRuntimeInfo *runtime_info;
1315 /* this check can be inlined in jitted code, too */
1316 runtime_info = class->runtime_info;
1317 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1318 return runtime_info->domain_vtables [domain->domain_id];
1319 if (class->exception_type)
1321 return mono_class_create_runtime_vtable (domain, class);
1325 * mono_class_try_get_vtable:
1326 * @domain: the application domain
1327 * @class: the class to initialize
1329 * This function tries to get the associated vtable from @class if
1330 * it was already created.
1333 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *class)
1335 MonoClassRuntimeInfo *runtime_info;
1339 runtime_info = class->runtime_info;
1340 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1341 return runtime_info->domain_vtables [domain->domain_id];
1346 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class)
1349 MonoClassRuntimeInfo *runtime_info, *old_info;
1350 MonoClassField *field;
1353 int imt_table_bytes = 0;
1354 guint32 vtable_size, class_size;
1356 guint32 constant_cols [MONO_CONSTANT_SIZE];
1358 gpointer *interface_offsets;
1360 mono_domain_lock (domain);
1361 runtime_info = class->runtime_info;
1362 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1363 mono_domain_unlock (domain);
1364 return runtime_info->domain_vtables [domain->domain_id];
1366 if (!class->inited || class->exception_type) {
1367 if (!mono_class_init (class) || class->exception_type){
1369 mono_domain_unlock (domain);
1370 exc = mono_class_get_exception_for_failure (class);
1372 mono_raise_exception (exc);
1376 mono_class_init (class);
1379 * For some classes, mono_class_init () already computed class->vtable_size, and
1380 * that is all that is needed because of the vtable trampolines.
1382 if (!class->vtable_size)
1383 mono_class_setup_vtable (class);
1385 if (class->exception_type) {
1386 mono_domain_unlock (domain);
1391 vtable_size = sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
1392 if (class->interface_offsets_count) {
1393 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1394 vtable_size += sizeof (gpointer) * (MONO_IMT_SIZE);
1395 mono_stats.imt_number_of_tables++;
1396 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
1399 vtable_size = sizeof (gpointer) * (class->max_interface_id + 1) +
1400 sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
1403 mono_stats.used_class_count++;
1404 mono_stats.class_vtable_size += vtable_size;
1405 interface_offsets = mono_mempool_alloc0 (domain->mp, vtable_size);
1408 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1410 vt = (MonoVTable*) (interface_offsets + class->max_interface_id + 1);
1412 vt->rank = class->rank;
1413 vt->domain = domain;
1415 mono_class_compute_gc_descriptor (class);
1417 * We can't use typed allocation in the non-root domains, since the
1418 * collector needs the GC descriptor stored in the vtable even after
1419 * the mempool containing the vtable is destroyed when the domain is
1420 * unloaded. An alternative might be to allocate vtables in the GC
1421 * heap, but this does not seem to work (it leads to crashes inside
1422 * libgc). If that approach is tried, two gc descriptors need to be
1423 * allocated for each class: one for the root domain, and one for all
1424 * other domains. The second descriptor should contain a bit for the
1425 * vtable field in MonoObject, since we can no longer assume the
1426 * vtable is reachable by other roots after the appdomain is unloaded.
1428 #ifdef HAVE_BOEHM_GC
1429 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1430 vt->gc_descr = GC_NO_DESCRIPTOR;
1433 vt->gc_descr = class->gc_descr;
1435 if ((class_size = mono_class_data_size (class))) {
1436 if (class->has_static_refs) {
1437 gpointer statics_gc_descr;
1439 gsize default_bitmap [4] = {0};
1442 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1443 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
1444 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set? max_set + 1: 0);
1445 vt->data = mono_gc_alloc_fixed (class_size, statics_gc_descr);
1446 mono_domain_add_class_static_data (domain, class, vt->data, NULL);
1447 if (bitmap != default_bitmap)
1450 vt->data = mono_mempool_alloc0 (domain->mp, class_size);
1452 mono_stats.class_static_data_size += class_size;
1457 while ((field = mono_class_get_fields (class, &iter))) {
1458 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1460 if (mono_field_is_deleted (field))
1462 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1463 gint32 special_static = class->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (class, field);
1464 if (special_static != SPECIAL_STATIC_NONE) {
1465 guint32 size, offset;
1467 size = mono_type_size (field->type, &align);
1468 offset = mono_alloc_special_static_data (special_static, size, align);
1469 if (!domain->special_static_fields)
1470 domain->special_static_fields = g_hash_table_new (NULL, NULL);
1471 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
1475 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
1476 MonoClass *fklass = mono_class_from_mono_type (field->type);
1477 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
1478 t = (char*)vt->data + field->offset;
1479 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
1482 if (fklass->valuetype) {
1483 memcpy (t, field->data, mono_class_value_size (fklass, NULL));
1485 /* it's a pointer type: add check */
1486 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
1487 *t = *(char *)field->data;
1491 if (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT))
1494 /* later do this only on demand if needed */
1496 cindex = mono_metadata_get_constant_index (class->image, mono_class_get_field_token (field), cindex + 1);
1498 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA));
1500 mono_metadata_decode_row (&class->image->tables [MONO_TABLE_CONSTANT], cindex - 1, constant_cols, MONO_CONSTANT_SIZE);
1501 field->def_type = constant_cols [MONO_CONSTANT_TYPE];
1502 field->data = (gpointer)mono_metadata_blob_heap (class->image, constant_cols [MONO_CONSTANT_VALUE]);
1507 vt->max_interface_id = class->max_interface_id;
1508 vt->interface_bitmap = class->interface_bitmap;
1510 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
1511 // class->name, class->interface_offsets_count);
1513 if (! ARCH_USE_IMT) {
1514 /* initialize interface offsets */
1515 for (i = 0; i < class->interface_offsets_count; ++i) {
1516 int interface_id = class->interfaces_packed [i]->interface_id;
1517 int slot = class->interface_offsets_packed [i];
1518 interface_offsets [class->max_interface_id - interface_id] = &(vt->vtable [slot]);
1522 /* FIXME: class_vtable_hash is basically obsolete now: remove as soon
1523 * as we change the code in appdomain.c to invalidate vtables by
1524 * looking at the possible MonoClasses created for the domain.
1526 g_hash_table_insert (domain->class_vtable_hash, class, vt);
1527 /* class->runtime_info is protected by the loader lock, both when
1528 * it it enlarged and when it is stored info.
1530 mono_loader_lock ();
1531 old_info = class->runtime_info;
1532 if (old_info && old_info->max_domain >= domain->domain_id) {
1533 /* someone already created a large enough runtime info */
1534 mono_memory_barrier ();
1535 old_info->domain_vtables [domain->domain_id] = vt;
1537 int new_size = domain->domain_id;
1539 new_size = MAX (new_size, old_info->max_domain);
1541 /* make the new size a power of two */
1543 while (new_size > i)
1546 /* this is a bounded memory retention issue: may want to
1547 * handle it differently when we'll have a rcu-like system.
1549 runtime_info = mono_mempool_alloc0 (class->image->mempool, sizeof (MonoClassRuntimeInfo) + new_size * sizeof (gpointer));
1550 runtime_info->max_domain = new_size - 1;
1551 /* copy the stuff from the older info */
1553 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
1555 runtime_info->domain_vtables [domain->domain_id] = vt;
1557 mono_memory_barrier ();
1558 class->runtime_info = runtime_info;
1560 mono_loader_unlock ();
1562 /* Initialize vtable */
1563 if (vtable_trampoline) {
1564 // This also covers the AOT case
1565 for (i = 0; i < class->vtable_size; ++i) {
1566 vt->vtable [i] = vtable_trampoline;
1569 mono_class_setup_vtable (class);
1571 for (i = 0; i < class->vtable_size; ++i) {
1574 if ((cm = class->vtable [i])) {
1575 if (mono_method_signature (cm)->generic_param_count)
1576 /* FIXME: Why is this needed ? */
1577 vt->vtable [i] = cm;
1579 vt->vtable [i] = vtable_trampoline? vtable_trampoline: arch_create_jit_trampoline (cm);
1584 if (ARCH_USE_IMT && imt_table_bytes) {
1585 /* Now that the vtable is full, we can actually fill up the IMT */
1586 if (imt_trampoline) {
1587 /* lazy construction of the IMT entries enabled */
1588 for (i = 0; i < MONO_IMT_SIZE; ++i)
1589 interface_offsets [i] = imt_trampoline;
1591 build_imt (class, vt, domain, interface_offsets, NULL);
1595 mono_domain_unlock (domain);
1597 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
1598 if (mono_is_security_manager_active () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND)) {
1599 MonoException *exc = mono_class_get_exception_for_failure (class);
1601 mono_raise_exception (exc);
1604 /* make sure the parent is initialized */
1606 mono_class_vtable (domain, class->parent);
1608 vt->type = mono_type_get_object (domain, &class->byval_arg);
1609 if (class->contextbound)
1618 * mono_class_proxy_vtable:
1619 * @domain: the application domain
1620 * @remove_class: the remote class
1622 * Creates a vtable for transparent proxies. It is basically
1623 * a copy of the real vtable of the class wrapped in @remote_class,
1624 * but all function pointers invoke the remoting functions, and
1625 * vtable->klass points to the transparent proxy class, and not to @class.
1628 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
1630 MonoVTable *vt, *pvt;
1631 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
1633 GSList *extra_interfaces = NULL;
1634 MonoClass *class = remote_class->proxy_class;
1635 gpointer *interface_offsets;
1637 vt = mono_class_vtable (domain, class);
1638 max_interface_id = vt->max_interface_id;
1640 /* Calculate vtable space for extra interfaces */
1641 for (j = 0; j < remote_class->interface_count; j++) {
1642 MonoClass* iclass = remote_class->interfaces[j];
1646 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
1647 continue; /* interface implemented by the class */
1648 if (g_slist_find (extra_interfaces, iclass))
1651 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
1653 method_count = mono_class_num_methods (iclass);
1655 ifaces = mono_class_get_implemented_interfaces (iclass);
1657 for (i = 0; i < ifaces->len; ++i) {
1658 MonoClass *ic = g_ptr_array_index (ifaces, i);
1659 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
1660 continue; /* interface implemented by the class */
1661 if (g_slist_find (extra_interfaces, ic))
1663 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
1664 method_count += mono_class_num_methods (ic);
1666 g_ptr_array_free (ifaces, TRUE);
1669 extra_interface_vtsize += method_count * sizeof (gpointer);
1670 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
1674 mono_stats.imt_number_of_tables++;
1675 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
1676 vtsize = sizeof (gpointer) * (MONO_IMT_SIZE) +
1677 sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
1679 vtsize = sizeof (gpointer) * (max_interface_id + 1) +
1680 sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
1683 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
1685 interface_offsets = mono_mempool_alloc0 (domain->mp, vtsize + extra_interface_vtsize);
1687 pvt = (MonoVTable*) (interface_offsets + MONO_IMT_SIZE);
1689 pvt = (MonoVTable*) (interface_offsets + max_interface_id + 1);
1690 memcpy (pvt, vt, sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer));
1692 pvt->klass = mono_defaults.transparent_proxy_class;
1693 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
1694 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
1696 /* initialize vtable */
1697 mono_class_setup_vtable (class);
1698 for (i = 0; i < class->vtable_size; ++i) {
1701 if ((cm = class->vtable [i]))
1702 pvt->vtable [i] = mono_method_signature (cm)->generic_param_count
1703 ? cm : arch_create_remoting_trampoline (cm, target_type);
1705 pvt->vtable [i] = NULL;
1708 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
1709 /* create trampolines for abstract methods */
1710 for (k = class; k; k = k->parent) {
1712 gpointer iter = NULL;
1713 while ((m = mono_class_get_methods (k, &iter)))
1714 if (!pvt->vtable [m->slot])
1715 pvt->vtable [m->slot] = mono_method_signature (m)->generic_param_count ? m : arch_create_remoting_trampoline (m, target_type);
1719 pvt->max_interface_id = max_interface_id;
1720 pvt->interface_bitmap = mono_mempool_alloc0 (domain->mp, sizeof (guint8) * (max_interface_id/8 + 1 ));
1722 if (! ARCH_USE_IMT) {
1723 /* initialize interface offsets */
1724 for (i = 0; i < class->interface_offsets_count; ++i) {
1725 int interface_id = class->interfaces_packed [i]->interface_id;
1726 int slot = class->interface_offsets_packed [i];
1727 interface_offsets [class->max_interface_id - interface_id] = &(pvt->vtable [slot]);
1730 for (i = 0; i < class->interface_offsets_count; ++i) {
1731 int interface_id = class->interfaces_packed [i]->interface_id;
1732 pvt->interface_bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
1735 if (extra_interfaces) {
1736 int slot = class->vtable_size;
1742 /* Create trampolines for the methods of the interfaces */
1743 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1744 interf = list_item->data;
1746 if (! ARCH_USE_IMT) {
1747 interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
1749 pvt->interface_bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
1753 while ((cm = mono_class_get_methods (interf, &iter)))
1754 pvt->vtable [slot + j++] = mono_method_signature (cm)->generic_param_count ? cm : arch_create_remoting_trampoline (cm, target_type);
1756 slot += mono_class_num_methods (interf);
1758 if (! ARCH_USE_IMT) {
1759 g_slist_free (extra_interfaces);
1764 /* Now that the vtable is full, we can actually fill up the IMT */
1765 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
1766 if (extra_interfaces) {
1767 g_slist_free (extra_interfaces);
1775 * mono_class_field_is_special_static:
1777 * Returns whether @field is a thread/context static field.
1780 mono_class_field_is_special_static (MonoClassField *field)
1782 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1784 if (mono_field_is_deleted (field))
1786 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1787 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
1794 * mono_class_has_special_static_fields:
1796 * Returns whenever @klass has any thread/context static fields.
1799 mono_class_has_special_static_fields (MonoClass *klass)
1801 MonoClassField *field;
1805 while ((field = mono_class_get_fields (klass, &iter))) {
1806 g_assert (field->parent == klass);
1807 if (mono_class_field_is_special_static (field))
1815 * create_remote_class_key:
1816 * Creates an array of pointers that can be used as a hash key for a remote class.
1817 * The first element of the array is the number of pointers.
1820 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
1825 if (remote_class == NULL) {
1826 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1827 key = g_malloc (sizeof(gpointer) * 3);
1828 key [0] = GINT_TO_POINTER (2);
1829 key [1] = mono_defaults.marshalbyrefobject_class;
1830 key [2] = extra_class;
1832 key = g_malloc (sizeof(gpointer) * 2);
1833 key [0] = GINT_TO_POINTER (1);
1834 key [1] = extra_class;
1837 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
1838 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
1839 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
1840 key [1] = remote_class->proxy_class;
1842 // Keep the list of interfaces sorted
1843 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
1844 if (extra_class && remote_class->interfaces [i] > extra_class) {
1845 key [j++] = extra_class;
1848 key [j] = remote_class->interfaces [i];
1851 key [j] = extra_class;
1853 // Replace the old class. The interface list is the same
1854 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
1855 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
1856 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
1857 for (i = 0; i < remote_class->interface_count; i++)
1858 key [2 + i] = remote_class->interfaces [i];
1866 * copy_remote_class_key:
1868 * Make a copy of KEY in the mempool MP and return the copy.
1871 copy_remote_class_key (MonoMemPool *mp, gpointer *key)
1873 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
1874 gpointer *mp_key = mono_mempool_alloc (mp, key_size);
1876 memcpy (mp_key, key, key_size);
1882 * mono_remote_class:
1883 * @domain: the application domain
1884 * @class_name: name of the remote class
1886 * Creates and initializes a MonoRemoteClass object for a remote type.
1890 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
1892 MonoRemoteClass *rc;
1893 gpointer* key, *mp_key;
1895 key = create_remote_class_key (NULL, proxy_class);
1897 mono_domain_lock (domain);
1898 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
1902 mono_domain_unlock (domain);
1906 mp_key = copy_remote_class_key (domain->mp, key);
1910 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1911 rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass) + sizeof(MonoClass*));
1912 rc->interface_count = 1;
1913 rc->interfaces [0] = proxy_class;
1914 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
1916 rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass));
1917 rc->interface_count = 0;
1918 rc->proxy_class = proxy_class;
1921 rc->default_vtable = NULL;
1922 rc->xdomain_vtable = NULL;
1923 rc->proxy_class_name = mono_string_to_utf8_mp (domain->mp, class_name);
1925 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
1927 mono_domain_unlock (domain);
1932 * clone_remote_class:
1933 * Creates a copy of the remote_class, adding the provided class or interface
1935 static MonoRemoteClass*
1936 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
1938 MonoRemoteClass *rc;
1939 gpointer* key, *mp_key;
1941 key = create_remote_class_key (remote_class, extra_class);
1942 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
1948 mp_key = copy_remote_class_key (domain->mp, key);
1952 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1954 rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass) + sizeof(MonoClass*) * (remote_class->interface_count + 1));
1955 rc->proxy_class = remote_class->proxy_class;
1956 rc->interface_count = remote_class->interface_count + 1;
1958 // Keep the list of interfaces sorted, since the hash key of
1959 // the remote class depends on this
1960 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
1961 if (remote_class->interfaces [i] > extra_class && i == j)
1962 rc->interfaces [j++] = extra_class;
1963 rc->interfaces [j] = remote_class->interfaces [i];
1966 rc->interfaces [j] = extra_class;
1968 // Replace the old class. The interface array is the same
1969 rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass) + sizeof(MonoClass*) * remote_class->interface_count);
1970 rc->proxy_class = extra_class;
1971 rc->interface_count = remote_class->interface_count;
1972 if (rc->interface_count > 0)
1973 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
1976 rc->default_vtable = NULL;
1977 rc->xdomain_vtable = NULL;
1978 rc->proxy_class_name = remote_class->proxy_class_name;
1980 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
1986 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
1988 mono_domain_lock (domain);
1989 if (rp->target_domain_id != -1) {
1990 if (remote_class->xdomain_vtable == NULL)
1991 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
1992 mono_domain_unlock (domain);
1993 return remote_class->xdomain_vtable;
1995 if (remote_class->default_vtable == NULL) {
1998 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
1999 klass = mono_class_from_mono_type (type);
2000 if ((klass->is_com_object || (mono_defaults.com_object_class && klass == mono_defaults.com_object_class)) && !mono_class_vtable (mono_domain_get (), klass)->remote)
2001 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2003 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2006 mono_domain_unlock (domain);
2007 return remote_class->default_vtable;
2011 * mono_upgrade_remote_class:
2012 * @domain: the application domain
2013 * @tproxy: the proxy whose remote class has to be upgraded.
2014 * @klass: class to which the remote class can be casted.
2016 * Updates the vtable of the remote class by adding the necessary method slots
2017 * and interface offsets so it can be safely casted to klass. klass can be a
2018 * class or an interface.
2021 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2023 MonoTransparentProxy *tproxy;
2024 MonoRemoteClass *remote_class;
2025 gboolean redo_vtable;
2027 mono_domain_lock (domain);
2029 tproxy = (MonoTransparentProxy*) proxy_object;
2030 remote_class = tproxy->remote_class;
2032 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2035 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2036 if (remote_class->interfaces [i] == klass)
2037 redo_vtable = FALSE;
2040 redo_vtable = (remote_class->proxy_class != klass);
2044 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2045 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2048 mono_domain_unlock (domain);
2053 * mono_object_get_virtual_method:
2054 * @obj: object to operate on.
2057 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2058 * the instance of a callvirt of method.
2061 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2064 MonoMethod **vtable;
2066 MonoMethod *res = NULL;
2068 klass = mono_object_class (obj);
2069 if (klass == mono_defaults.transparent_proxy_class) {
2070 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2076 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2079 mono_class_setup_vtable (klass);
2080 vtable = klass->vtable;
2082 /* check method->slot is a valid index: perform isinstance? */
2083 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2085 res = vtable [mono_class_interface_offset (klass, method->klass) + method->slot];
2087 if (method->slot != -1) {
2088 res = vtable [method->slot];
2090 /* method->slot might not be set for instances of generic methods in the AOT case */
2091 if (method->is_inflated) {
2092 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2093 res = vtable [((MonoMethodInflated*)method)->declaring->slot];
2099 /* It may be an interface, abstract class method or generic method */
2100 if (!res || mono_method_signature (res)->generic_param_count)
2103 /* generic methods demand invoke_with_check */
2104 if (mono_method_signature (res)->generic_param_count)
2105 res = mono_marshal_get_remoting_invoke_with_check (res);
2107 res = mono_marshal_get_remoting_invoke (res);
2109 if (method->is_inflated && !res->is_inflated) {
2110 /* Have to inflate the result */
2111 res = mono_class_inflate_generic_method (res, &((MonoMethodInflated*)method)->context);
2121 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2123 g_error ("runtime invoke called on uninitialized runtime");
2127 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2130 * mono_runtime_invoke:
2131 * @method: method to invoke
2132 * @obJ: object instance
2133 * @params: arguments to the method
2134 * @exc: exception information.
2136 * Invokes the method represented by @method on the object @obj.
2138 * obj is the 'this' pointer, it should be NULL for static
2139 * methods, a MonoObject* for object instances and a pointer to
2140 * the value type for value types.
2142 * The params array contains the arguments to the method with the
2143 * same convention: MonoObject* pointers for object instances and
2144 * pointers to the value type otherwise.
2146 * From unmanaged code you'll usually use the
2147 * mono_runtime_invoke() variant.
2149 * Note that this function doesn't handle virtual methods for
2150 * you, it will exec the exact method you pass: we still need to
2151 * expose a function to lookup the derived class implementation
2152 * of a virtual method (there are examples of this in the code,
2155 * You can pass NULL as the exc argument if you don't want to
2156 * catch exceptions, otherwise, *exc will be set to the exception
2157 * thrown, if any. if an exception is thrown, you can't use the
2158 * MonoObject* result from the function.
2160 * If the method returns a value type, it is boxed in an object
2164 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2166 if (mono_runtime_get_no_exec ())
2167 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2169 return default_mono_runtime_invoke (method, obj, params, exc);
2173 * mono_method_get_unmanaged_thunk:
2174 * @method: method to generate a thunk for.
2176 * Returns an unmanaged->managed thunk that can be used to call
2177 * a managed method directly from C.
2179 * The thunk's C signature closely matches the managed signature:
2181 * C#: public bool Equals (object obj);
2182 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2183 * MonoObject*, MonoException**);
2185 * The 1st ("this") parameter must not be used with static methods:
2187 * C#: public static bool ReferenceEquals (object a, object b);
2188 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2191 * The last argument must be a non-null pointer of a MonoException* pointer.
2192 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2193 * exception has been thrown in managed code. Otherwise it will point
2194 * to the MonoException* caught by the thunk. In this case, the result of
2195 * the thunk is undefined:
2197 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2198 * MonoException *ex = NULL;
2199 * Equals func = mono_method_get_unmanaged_thunk (method);
2200 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2202 * // handle exception
2205 * The calling convention of the thunk matches the platform's default
2206 * convention. This means that under Windows, C declarations must
2207 * contain the __stdcall attribute:
2209 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2210 * MonoObject*, MonoException**);
2214 * Value type arguments and return values are treated as they were objects:
2216 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2217 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2219 * Arguments must be properly boxed upon trunk's invocation, while return
2220 * values must be unboxed.
2223 mono_method_get_unmanaged_thunk (MonoMethod *method)
2225 method = mono_marshal_get_thunk_invoke_wrapper (method);
2226 return mono_compile_method (method);
2230 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
2234 gpointer *p = (gpointer*)dest;
2241 case MONO_TYPE_BOOLEAN:
2243 case MONO_TYPE_U1: {
2244 guint8 *p = (guint8*)dest;
2245 *p = value ? *(guint8*)value : 0;
2250 case MONO_TYPE_CHAR: {
2251 guint16 *p = (guint16*)dest;
2252 *p = value ? *(guint16*)value : 0;
2255 #if SIZEOF_VOID_P == 4
2260 case MONO_TYPE_U4: {
2261 gint32 *p = (gint32*)dest;
2262 *p = value ? *(gint32*)value : 0;
2265 #if SIZEOF_VOID_P == 8
2270 case MONO_TYPE_U8: {
2271 gint64 *p = (gint64*)dest;
2272 *p = value ? *(gint64*)value : 0;
2275 case MONO_TYPE_R4: {
2276 float *p = (float*)dest;
2277 *p = value ? *(float*)value : 0;
2280 case MONO_TYPE_R8: {
2281 double *p = (double*)dest;
2282 *p = value ? *(double*)value : 0;
2285 case MONO_TYPE_STRING:
2286 case MONO_TYPE_SZARRAY:
2287 case MONO_TYPE_CLASS:
2288 case MONO_TYPE_OBJECT:
2289 case MONO_TYPE_ARRAY:
2290 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2292 case MONO_TYPE_FNPTR:
2293 case MONO_TYPE_PTR: {
2294 gpointer *p = (gpointer*)dest;
2295 *p = deref_pointer? *(gpointer*)value: value;
2298 case MONO_TYPE_VALUETYPE:
2299 /* note that 't' and 'type->type' can be different */
2300 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
2301 t = type->data.klass->enum_basetype->type;
2305 size = mono_class_value_size (mono_class_from_mono_type (type), NULL);
2307 memset (dest, 0, size);
2309 memcpy (dest, value, size);
2312 case MONO_TYPE_GENERICINST:
2313 t = type->data.generic_class->container_class->byval_arg.type;
2316 g_warning ("got type %x", type->type);
2317 g_assert_not_reached ();
2322 * mono_field_set_value:
2323 * @obj: Instance object
2324 * @field: MonoClassField describing the field to set
2325 * @value: The value to be set
2327 * Sets the value of the field described by @field in the object instance @obj
2328 * to the value passed in @value. This method should only be used for instance
2329 * fields. For static fields, use mono_field_static_set_value.
2331 * The value must be on the native format of the field type.
2334 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
2338 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2340 dest = (char*)obj + field->offset;
2341 set_value (field->type, dest, value, FALSE);
2345 * mono_field_static_set_value:
2346 * @field: MonoClassField describing the field to set
2347 * @value: The value to be set
2349 * Sets the value of the static field described by @field
2350 * to the value passed in @value.
2352 * The value must be on the native format of the field type.
2355 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
2359 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2360 /* you cant set a constant! */
2361 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
2363 dest = (char*)vt->data + field->offset;
2364 set_value (field->type, dest, value, FALSE);
2367 /* Used by the debugger */
2369 mono_vtable_get_static_field_data (MonoVTable *vt)
2375 * mono_field_get_value:
2376 * @obj: Object instance
2377 * @field: MonoClassField describing the field to fetch information from
2378 * @value: pointer to the location where the value will be stored
2380 * Use this routine to get the value of the field @field in the object
2383 * The pointer provided by value must be of the field type, for reference
2384 * types this is a MonoObject*, for value types its the actual pointer to
2389 * mono_field_get_value (obj, int_field, &i);
2392 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
2396 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2398 src = (char*)obj + field->offset;
2399 set_value (field->type, value, src, TRUE);
2403 * mono_field_get_value_object:
2404 * @domain: domain where the object will be created (if boxing)
2405 * @field: MonoClassField describing the field to fetch information from
2406 * @obj: The object instance for the field.
2408 * Returns: a new MonoObject with the value from the given field. If the
2409 * field represents a value type, the value is boxed.
2413 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
2417 MonoVTable *vtable = NULL;
2419 gboolean is_static = FALSE;
2420 gboolean is_ref = FALSE;
2422 switch (field->type->type) {
2423 case MONO_TYPE_STRING:
2424 case MONO_TYPE_OBJECT:
2425 case MONO_TYPE_CLASS:
2426 case MONO_TYPE_ARRAY:
2427 case MONO_TYPE_SZARRAY:
2432 case MONO_TYPE_BOOLEAN:
2435 case MONO_TYPE_CHAR:
2444 case MONO_TYPE_VALUETYPE:
2445 is_ref = field->type->byref;
2447 case MONO_TYPE_GENERICINST:
2448 is_ref = !field->type->data.generic_class->container_class->valuetype;
2451 g_error ("type 0x%x not handled in "
2452 "mono_field_get_value_object", field->type->type);
2456 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
2458 vtable = mono_class_vtable (domain, field->parent);
2459 if (!vtable->initialized)
2460 mono_runtime_class_init (vtable);
2465 mono_field_static_get_value (vtable, field, &o);
2467 mono_field_get_value (obj, field, &o);
2472 /* boxed value type */
2473 klass = mono_class_from_mono_type (field->type);
2474 o = mono_object_new (domain, klass);
2475 v = ((gchar *) o) + sizeof (MonoObject);
2477 mono_field_static_get_value (vtable, field, v);
2479 mono_field_get_value (obj, field, v);
2486 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
2489 const char *p = blob;
2490 mono_metadata_decode_blob_size (p, &p);
2493 case MONO_TYPE_BOOLEAN:
2496 *(guint8 *) value = *p;
2498 case MONO_TYPE_CHAR:
2501 *(guint16*) value = read16 (p);
2505 *(guint32*) value = read32 (p);
2509 *(guint64*) value = read64 (p);
2512 readr4 (p, (float*) value);
2515 readr8 (p, (double*) value);
2517 case MONO_TYPE_STRING:
2518 *(gpointer*) value = mono_ldstr_metdata_sig (domain, blob);
2520 case MONO_TYPE_CLASS:
2521 *(gpointer*) value = NULL;
2525 g_warning ("type 0x%02x should not be in constant table", type);
2531 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
2533 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT);
2534 mono_get_constant_value_from_blob (domain, field->def_type, field->data, value);
2538 * mono_field_static_get_value:
2539 * @vt: vtable to the object
2540 * @field: MonoClassField describing the field to fetch information from
2541 * @value: where the value is returned
2543 * Use this routine to get the value of the static field @field value.
2545 * The pointer provided by value must be of the field type, for reference
2546 * types this is a MonoObject*, for value types its the actual pointer to
2551 * mono_field_static_get_value (vt, int_field, &i);
2554 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
2558 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2560 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
2561 get_default_field_value (vt->domain, field, value);
2565 src = (char*)vt->data + field->offset;
2566 set_value (field->type, value, src, TRUE);
2570 * mono_property_set_value:
2571 * @prop: MonoProperty to set
2572 * @obj: instance object on which to act
2573 * @params: parameters to pass to the propery
2574 * @exc: optional exception
2576 * Invokes the property's set method with the given arguments on the
2577 * object instance obj (or NULL for static properties).
2579 * You can pass NULL as the exc argument if you don't want to
2580 * catch exceptions, otherwise, *exc will be set to the exception
2581 * thrown, if any. if an exception is thrown, you can't use the
2582 * MonoObject* result from the function.
2585 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
2587 default_mono_runtime_invoke (prop->set, obj, params, exc);
2591 * mono_property_get_value:
2592 * @prop: MonoProperty to fetch
2593 * @obj: instance object on which to act
2594 * @params: parameters to pass to the propery
2595 * @exc: optional exception
2597 * Invokes the property's get method with the given arguments on the
2598 * object instance obj (or NULL for static properties).
2600 * You can pass NULL as the exc argument if you don't want to
2601 * catch exceptions, otherwise, *exc will be set to the exception
2602 * thrown, if any. if an exception is thrown, you can't use the
2603 * MonoObject* result from the function.
2605 * Returns: the value from invoking the get method on the property.
2608 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
2610 return default_mono_runtime_invoke (prop->get, obj, params, exc);
2614 * mono_nullable_init:
2615 * @buf: The nullable structure to initialize.
2616 * @value: the value to initialize from
2617 * @klass: the type for the object
2619 * Initialize the nullable structure pointed to by @buf from @value which
2620 * should be a boxed value type. The size of @buf should be able to hold
2621 * as much data as the @klass->instance_size (which is the number of bytes
2622 * that will be copies).
2624 * Since Nullables have variable structure, we can not define a C
2625 * structure for them.
2628 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
2630 MonoClass *param_class = klass->cast_class;
2632 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
2633 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
2635 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
2637 memcpy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
2639 memset (buf + klass->fields [0].offset - sizeof (MonoObject), 0, mono_class_value_size (param_class, NULL));
2643 * mono_nullable_box:
2644 * @buf: The buffer representing the data to be boxed
2645 * @klass: the type to box it as.
2647 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
2651 mono_nullable_box (guint8 *buf, MonoClass *klass)
2653 MonoClass *param_class = klass->cast_class;
2655 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
2656 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
2658 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
2659 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
2660 memcpy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
2668 * mono_get_delegate_invoke:
2669 * @klass: The delegate class
2671 * Returns: the MonoMethod for the "Invoke" method in the delegate klass
2674 mono_get_delegate_invoke (MonoClass *klass)
2678 im = mono_class_get_method_from_name (klass, "Invoke", -1);
2685 * mono_runtime_delegate_invoke:
2686 * @delegate: pointer to a delegate object.
2687 * @params: parameters for the delegate.
2688 * @exc: Pointer to the exception result.
2690 * Invokes the delegate method @delegate with the parameters provided.
2692 * You can pass NULL as the exc argument if you don't want to
2693 * catch exceptions, otherwise, *exc will be set to the exception
2694 * thrown, if any. if an exception is thrown, you can't use the
2695 * MonoObject* result from the function.
2698 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
2702 im = mono_get_delegate_invoke (delegate->vtable->klass);
2705 return mono_runtime_invoke (im, delegate, params, exc);
2708 static char **main_args = NULL;
2709 static int num_main_args;
2712 * mono_runtime_get_main_args:
2714 * Returns: a MonoArray with the arguments passed to the main program
2717 mono_runtime_get_main_args (void)
2721 MonoDomain *domain = mono_domain_get ();
2726 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
2728 for (i = 0; i < num_main_args; ++i)
2729 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
2735 fire_process_exit_event (void)
2737 MonoClassField *field;
2738 MonoDomain *domain = mono_domain_get ();
2740 MonoObject *delegate, *exc;
2742 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "ProcessExit");
2745 if (domain != mono_get_root_domain ())
2748 delegate = *(MonoObject **)(((char *)domain->domain) + field->offset);
2749 if (delegate == NULL)
2754 mono_runtime_delegate_invoke (delegate, pa, &exc);
2758 * mono_runtime_run_main:
2759 * @method: the method to start the application with (usually Main)
2760 * @argc: number of arguments from the command line
2761 * @argv: array of strings from the command line
2762 * @exc: excetption results
2764 * Execute a standard Main() method (argc/argv contains the
2765 * executable name). This method also sets the command line argument value
2766 * needed by System.Environment.
2771 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
2775 MonoArray *args = NULL;
2776 MonoDomain *domain = mono_domain_get ();
2777 gchar *utf8_fullpath;
2780 g_assert (method != NULL);
2782 mono_thread_set_main (mono_thread_current ());
2784 main_args = g_new0 (char*, argc);
2785 num_main_args = argc;
2787 if (!g_path_is_absolute (argv [0])) {
2788 gchar *basename = g_path_get_basename (argv [0]);
2789 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
2793 utf8_fullpath = mono_utf8_from_external (fullpath);
2794 if(utf8_fullpath == NULL) {
2795 /* Printing the arg text will cause glib to
2796 * whinge about "Invalid UTF-8", but at least
2797 * its relevant, and shows the problem text
2800 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
2801 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
2808 utf8_fullpath = mono_utf8_from_external (argv[0]);
2809 if(utf8_fullpath == NULL) {
2810 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
2811 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
2816 main_args [0] = utf8_fullpath;
2818 for (i = 1; i < argc; ++i) {
2821 utf8_arg=mono_utf8_from_external (argv[i]);
2822 if(utf8_arg==NULL) {
2823 /* Ditto the comment about Invalid UTF-8 here */
2824 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
2825 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
2829 main_args [i] = utf8_arg;
2833 if (mono_method_signature (method)->param_count) {
2834 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
2835 for (i = 0; i < argc; ++i) {
2836 /* The encodings should all work, given that
2837 * we've checked all these args for the
2840 gchar *str = mono_utf8_from_external (argv [i]);
2841 MonoString *arg = mono_string_new (domain, str);
2842 mono_array_setref (args, i, arg);
2846 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
2849 mono_assembly_set_main (method->klass->image->assembly);
2851 result = mono_runtime_exec_main (method, args, exc);
2852 fire_process_exit_event ();
2856 /* Used in call_unhandled_exception_delegate */
2858 create_unhandled_exception_eventargs (MonoObject *exc)
2862 MonoMethod *method = NULL;
2863 MonoBoolean is_terminating = TRUE;
2866 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
2869 mono_class_init (klass);
2871 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
2872 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
2876 args [1] = &is_terminating;
2878 obj = mono_object_new (mono_domain_get (), klass);
2879 mono_runtime_invoke (method, obj, args, NULL);
2884 /* Used in mono_unhandled_exception */
2886 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
2887 MonoObject *e = NULL;
2890 pa [0] = domain->domain;
2891 pa [1] = create_unhandled_exception_eventargs (exc);
2892 mono_runtime_delegate_invoke (delegate, pa, &e);
2895 gchar *msg = mono_string_to_utf8 (((MonoException *) e)->message);
2896 g_warning ("exception inside UnhandledException handler: %s\n", msg);
2901 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANLED_POLICY_CURRENT;
2904 * mono_runtime_unhandled_exception_policy_set:
2905 * @policy: the new policy
2907 * This is a VM internal routine.
2909 * Sets the runtime policy for handling unhandled exceptions.
2912 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
2913 runtime_unhandled_exception_policy = policy;
2917 * mono_runtime_unhandled_exception_policy_get:
2919 * This is a VM internal routine.
2921 * Gets the runtime policy for handling unhandled exceptions.
2923 MonoRuntimeUnhandledExceptionPolicy
2924 mono_runtime_unhandled_exception_policy_get (void) {
2925 return runtime_unhandled_exception_policy;
2929 * mono_unhandled_exception:
2930 * @exc: exception thrown
2932 * This is a VM internal routine.
2934 * We call this function when we detect an unhandled exception
2935 * in the default domain.
2937 * It invokes the * UnhandledException event in AppDomain or prints
2938 * a warning to the console
2941 mono_unhandled_exception (MonoObject *exc)
2943 MonoDomain *current_domain = mono_domain_get ();
2944 MonoDomain *root_domain = mono_get_root_domain ();
2945 MonoClassField *field;
2946 MonoObject *current_appdomain_delegate;
2947 MonoObject *root_appdomain_delegate;
2949 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
2950 "UnhandledException");
2953 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
2954 gboolean abort_process = (mono_thread_current () == main_thread) ||
2955 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANLED_POLICY_CURRENT);
2956 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
2957 if (current_domain != root_domain && (mono_get_runtime_info ()->framework_version [0] >= '2')) {
2958 current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
2960 current_appdomain_delegate = NULL;
2963 /* set exitcode only if we will abort the process */
2965 mono_environment_exitcode_set (1);
2966 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
2967 mono_print_unhandled_exception (exc);
2969 if (root_appdomain_delegate) {
2970 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
2972 if (current_appdomain_delegate) {
2973 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
2980 * Launch a new thread to execute a function
2982 * main_func is called back from the thread with main_args as the
2983 * parameter. The callback function is expected to start Main()
2984 * eventually. This function then waits for all managed threads to
2986 * It is not necesseray anymore to execute managed code in a subthread,
2987 * so this function should not be used anymore by default: just
2988 * execute the code and then call mono_thread_manage ().
2991 mono_runtime_exec_managed_code (MonoDomain *domain,
2992 MonoMainThreadFunc main_func,
2995 mono_thread_create (domain, main_func, main_args);
2997 mono_thread_manage ();
3001 * Execute a standard Main() method (args doesn't contain the
3005 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
3010 MonoCustomAttrInfo* cinfo;
3011 gboolean has_stathread_attribute;
3012 MonoThread* thread = mono_thread_current ();
3018 domain = mono_object_domain (args);
3019 if (!domain->entry_assembly) {
3021 MonoAssembly *assembly;
3023 assembly = method->klass->image->assembly;
3024 domain->entry_assembly = assembly;
3025 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
3027 str = g_strconcat (assembly->image->name, ".config", NULL);
3028 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
3032 cinfo = mono_custom_attrs_from_method (method);
3034 static MonoClass *stathread_attribute = NULL;
3035 if (!stathread_attribute)
3036 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
3037 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
3039 mono_custom_attrs_free (cinfo);
3041 has_stathread_attribute = FALSE;
3043 if (has_stathread_attribute) {
3044 thread->apartment_state = ThreadApartmentState_STA;
3045 } else if (mono_get_runtime_info ()->framework_version [0] == '1') {
3046 thread->apartment_state = ThreadApartmentState_Unknown;
3048 thread->apartment_state = ThreadApartmentState_MTA;
3050 mono_thread_init_apartment_state ();
3052 mono_debugger_event (MONO_DEBUGGER_EVENT_REACHED_MAIN, 0, 0);
3054 /* FIXME: check signature of method */
3055 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
3057 res = mono_runtime_invoke (method, NULL, pa, exc);
3059 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
3063 mono_environment_exitcode_set (rval);
3065 mono_runtime_invoke (method, NULL, pa, exc);
3069 /* If the return type of Main is void, only
3070 * set the exitcode if an exception was thrown
3071 * (we don't want to blow away an
3072 * explicitly-set exit code)
3075 mono_environment_exitcode_set (rval);
3079 mono_debugger_event (MONO_DEBUGGER_EVENT_MAIN_EXITED, (guint64) (gsize) rval, 0);
3085 * mono_install_runtime_invoke:
3086 * @func: Function to install
3088 * This is a VM internal routine
3091 mono_install_runtime_invoke (MonoInvokeFunc func)
3093 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
3098 * mono_runtime_invoke_array:
3099 * @method: method to invoke
3100 * @obJ: object instance
3101 * @params: arguments to the method
3102 * @exc: exception information.
3104 * Invokes the method represented by @method on the object @obj.
3106 * obj is the 'this' pointer, it should be NULL for static
3107 * methods, a MonoObject* for object instances and a pointer to
3108 * the value type for value types.
3110 * The params array contains the arguments to the method with the
3111 * same convention: MonoObject* pointers for object instances and
3112 * pointers to the value type otherwise. The _invoke_array
3113 * variant takes a C# object[] as the params argument (MonoArray
3114 * *params): in this case the value types are boxed inside the
3115 * respective reference representation.
3117 * From unmanaged code you'll usually use the
3118 * mono_runtime_invoke() variant.
3120 * Note that this function doesn't handle virtual methods for
3121 * you, it will exec the exact method you pass: we still need to
3122 * expose a function to lookup the derived class implementation
3123 * of a virtual method (there are examples of this in the code,
3126 * You can pass NULL as the exc argument if you don't want to
3127 * catch exceptions, otherwise, *exc will be set to the exception
3128 * thrown, if any. if an exception is thrown, you can't use the
3129 * MonoObject* result from the function.
3131 * If the method returns a value type, it is boxed in an object
3135 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
3138 MonoMethodSignature *sig = mono_method_signature (method);
3139 gpointer *pa = NULL;
3142 if (NULL != params) {
3143 pa = alloca (sizeof (gpointer) * mono_array_length (params));
3144 for (i = 0; i < mono_array_length (params); i++) {
3145 MonoType *t = sig->params [i];
3151 case MONO_TYPE_BOOLEAN:
3154 case MONO_TYPE_CHAR:
3163 case MONO_TYPE_VALUETYPE:
3164 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
3167 g_assert_not_reached ();
3168 /* The runtime invoke wrapper needs the original boxed vtype */
3169 pa [i] = mono_array_get (params, MonoObject*, i);
3171 /* MS seems to create the objects if a null is passed in */
3172 if (!mono_array_get (params, MonoObject*, i))
3173 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
3177 * We can't pass the unboxed vtype byref to the callee, since
3178 * that would mean the callee would be able to modify boxed
3179 * primitive types. So we (and MS) make a copy of the boxed
3180 * object, pass that to the callee, and replace the original
3181 * boxed object in the arg array with the copy.
3183 MonoObject *orig = mono_array_get (params, MonoObject*, i);
3184 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
3185 mono_array_setref (params, i, copy);
3188 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
3191 case MONO_TYPE_STRING:
3192 case MONO_TYPE_OBJECT:
3193 case MONO_TYPE_CLASS:
3194 case MONO_TYPE_ARRAY:
3195 case MONO_TYPE_SZARRAY:
3197 pa [i] = mono_array_addr (params, MonoObject*, i);
3198 // FIXME: I need to check this code path
3200 pa [i] = mono_array_get (params, MonoObject*, i);
3202 case MONO_TYPE_GENERICINST:
3204 t = &t->data.generic_class->container_class->this_arg;
3206 t = &t->data.generic_class->container_class->byval_arg;
3209 g_error ("type 0x%x not handled in ves_icall_InternalInvoke", sig->params [i]->type);
3214 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
3217 if (mono_class_is_nullable (method->klass)) {
3218 /* Need to create a boxed vtype instead */
3224 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
3228 obj = mono_object_new (mono_domain_get (), method->klass);
3229 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
3230 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
3232 if (method->klass->valuetype)
3233 o = mono_object_unbox (obj);
3236 } else if (method->klass->valuetype) {
3237 obj = mono_value_box (mono_domain_get (), method->klass, obj);
3240 mono_runtime_invoke (method, o, pa, exc);
3243 if (mono_class_is_nullable (method->klass)) {
3244 MonoObject *nullable;
3246 /* Convert the unboxed vtype into a Nullable structure */
3247 nullable = mono_object_new (mono_domain_get (), method->klass);
3249 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
3250 obj = mono_object_unbox (nullable);
3253 /* obj must be already unboxed if needed */
3254 return mono_runtime_invoke (method, obj, pa, exc);
3259 arith_overflow (void)
3261 mono_raise_exception (mono_get_exception_overflow ());
3265 * mono_object_allocate:
3266 * @size: number of bytes to allocate
3268 * This is a very simplistic routine until we have our GC-aware
3271 * Returns: an allocated object of size @size, or NULL on failure.
3273 static inline void *
3274 mono_object_allocate (size_t size, MonoVTable *vtable)
3277 mono_stats.new_object_count++;
3278 ALLOC_OBJECT (o, vtable, size);
3284 * mono_object_allocate_ptrfree:
3285 * @size: number of bytes to allocate
3287 * Note that the memory allocated is not zeroed.
3288 * Returns: an allocated object of size @size, or NULL on failure.
3290 static inline void *
3291 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
3294 mono_stats.new_object_count++;
3295 ALLOC_PTRFREE (o, vtable, size);
3299 static inline void *
3300 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
3303 ALLOC_TYPED (o, size, vtable);
3304 mono_stats.new_object_count++;
3311 * @klass: the class of the object that we want to create
3313 * Returns: a newly created object whose definition is
3314 * looked up using @klass. This will not invoke any constructors,
3315 * so the consumer of this routine has to invoke any constructors on
3316 * its own to initialize the object.
3319 mono_object_new (MonoDomain *domain, MonoClass *klass)
3321 MONO_ARCH_SAVE_REGS;
3322 return mono_object_new_specific (mono_class_vtable (domain, klass));
3326 * mono_object_new_specific:
3327 * @vtable: the vtable of the object that we want to create
3329 * Returns: A newly created object with class and domain specified
3333 mono_object_new_specific (MonoVTable *vtable)
3337 MONO_ARCH_SAVE_REGS;
3339 /* check for is_com_object for COM Interop */
3340 if (vtable->remote || vtable->klass->is_com_object)
3343 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
3346 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
3349 mono_class_init (klass);
3351 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
3353 vtable->domain->create_proxy_for_type_method = im;
3356 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
3358 o = mono_runtime_invoke (im, NULL, pa, NULL);
3359 if (o != NULL) return o;
3362 return mono_object_new_alloc_specific (vtable);
3366 mono_object_new_alloc_specific (MonoVTable *vtable)
3370 if (!vtable->klass->has_references) {
3371 o = mono_object_new_ptrfree (vtable);
3372 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3373 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
3375 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
3376 o = mono_object_allocate (vtable->klass->instance_size, vtable);
3378 if (G_UNLIKELY (vtable->klass->has_finalize))
3379 mono_object_register_finalizer (o);
3381 if (G_UNLIKELY (profile_allocs))
3382 mono_profiler_allocation (o, vtable->klass);
3387 mono_object_new_fast (MonoVTable *vtable)
3390 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
3395 mono_object_new_ptrfree (MonoVTable *vtable)
3398 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
3399 #if NEED_TO_ZERO_PTRFREE
3400 /* an inline memset is much faster for the common vcase of small objects
3401 * note we assume the allocated size is a multiple of sizeof (void*).
3403 if (vtable->klass->instance_size < 128) {
3405 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
3406 p = (gpointer*)((char*)obj + sizeof (MonoObject));
3412 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
3419 mono_object_new_ptrfree_box (MonoVTable *vtable)
3422 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
3423 /* the object will be boxed right away, no need to memzero it */
3428 * mono_class_get_allocation_ftn:
3430 * @for_box: the object will be used for boxing
3431 * @pass_size_in_words:
3433 * Return the allocation function appropriate for the given class.
3437 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
3439 *pass_size_in_words = FALSE;
3441 if (!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
3442 profile_allocs = FALSE;
3444 if (vtable->klass->has_finalize || vtable->klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
3445 return mono_object_new_specific;
3447 if (!vtable->klass->has_references) {
3448 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
3450 return mono_object_new_ptrfree_box;
3451 return mono_object_new_ptrfree;
3454 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3456 return mono_object_new_fast;
3459 * FIXME: This is actually slower than mono_object_new_fast, because
3460 * of the overhead of parameter passing.
3463 *pass_size_in_words = TRUE;
3464 #ifdef GC_REDIRECT_TO_LOCAL
3465 return GC_local_gcj_fast_malloc;
3467 return GC_gcj_fast_malloc;
3472 return mono_object_new_specific;
3476 * mono_object_new_from_token:
3477 * @image: Context where the type_token is hosted
3478 * @token: a token of the type that we want to create
3480 * Returns: A newly created object whose definition is
3481 * looked up using @token in the @image image
3484 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
3488 class = mono_class_get (image, token);
3490 return mono_object_new (domain, class);
3495 * mono_object_clone:
3496 * @obj: the object to clone
3498 * Returns: A newly created object who is a shallow copy of @obj
3501 mono_object_clone (MonoObject *obj)
3506 size = obj->vtable->klass->instance_size;
3507 o = mono_object_allocate (size, obj->vtable);
3508 /* do not copy the sync state */
3509 memcpy ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
3512 if (obj->vtable->klass->has_references)
3513 mono_gc_wbarrier_object (o);
3515 if (G_UNLIKELY (profile_allocs))
3516 mono_profiler_allocation (o, obj->vtable->klass);
3518 if (obj->vtable->klass->has_finalize)
3519 mono_object_register_finalizer (o);
3524 * mono_array_full_copy:
3525 * @src: source array to copy
3526 * @dest: destination array
3528 * Copies the content of one array to another with exactly the same type and size.
3531 mono_array_full_copy (MonoArray *src, MonoArray *dest)
3533 mono_array_size_t size;
3534 MonoClass *klass = src->obj.vtable->klass;
3536 MONO_ARCH_SAVE_REGS;
3538 g_assert (klass == dest->obj.vtable->klass);
3540 size = mono_array_length (src);
3541 g_assert (size == mono_array_length (dest));
3542 size *= mono_array_element_size (klass);
3544 if (klass->element_class->valuetype) {
3545 if (klass->element_class->has_references)
3546 mono_value_copy_array (dest, 0, src, mono_array_length (src));
3548 memcpy (&dest->vector, &src->vector, size);
3550 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
3553 memcpy (&dest->vector, &src->vector, size);
3558 * mono_array_clone_in_domain:
3559 * @domain: the domain in which the array will be cloned into
3560 * @array: the array to clone
3562 * This routine returns a copy of the array that is hosted on the
3563 * specified MonoDomain.
3566 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
3569 mono_array_size_t size, i;
3570 mono_array_size_t *sizes;
3571 MonoClass *klass = array->obj.vtable->klass;
3573 MONO_ARCH_SAVE_REGS;
3575 if (array->bounds == NULL) {
3576 size = mono_array_length (array);
3577 o = mono_array_new_full (domain, klass, &size, NULL);
3579 size *= mono_array_element_size (klass);
3581 if (klass->element_class->valuetype) {
3582 if (klass->element_class->has_references)
3583 mono_value_copy_array (o, 0, array, mono_array_length (array));
3585 memcpy (&o->vector, &array->vector, size);
3587 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
3590 memcpy (&o->vector, &array->vector, size);
3595 sizes = alloca (klass->rank * sizeof(mono_array_size_t) * 2);
3596 size = mono_array_element_size (klass);
3597 for (i = 0; i < klass->rank; ++i) {
3598 sizes [i] = array->bounds [i].length;
3599 size *= array->bounds [i].length;
3600 sizes [i + klass->rank] = array->bounds [i].lower_bound;
3602 o = mono_array_new_full (domain, klass, sizes, sizes + klass->rank);
3604 if (klass->element_class->valuetype) {
3605 if (klass->element_class->has_references)
3606 mono_value_copy_array (o, 0, array, mono_array_length (array));
3608 memcpy (&o->vector, &array->vector, size);
3610 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
3613 memcpy (&o->vector, &array->vector, size);
3621 * @array: the array to clone
3623 * Returns: A newly created array who is a shallow copy of @array
3626 mono_array_clone (MonoArray *array)
3628 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
3631 /* helper macros to check for overflow when calculating the size of arrays */
3632 #ifdef MONO_BIG_ARRAYS
3633 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
3634 #define MYGUINT_MAX MYGUINT64_MAX
3635 #define CHECK_ADD_OVERFLOW_UN(a,b) \
3636 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
3637 #define CHECK_MUL_OVERFLOW_UN(a,b) \
3638 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
3639 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
3641 #define MYGUINT32_MAX 4294967295U
3642 #define MYGUINT_MAX MYGUINT32_MAX
3643 #define CHECK_ADD_OVERFLOW_UN(a,b) \
3644 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
3645 #define CHECK_MUL_OVERFLOW_UN(a,b) \
3646 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
3647 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
3651 * mono_array_new_full:
3652 * @domain: domain where the object is created
3653 * @array_class: array class
3654 * @lengths: lengths for each dimension in the array
3655 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
3657 * This routine creates a new array objects with the given dimensions,
3658 * lower bounds and type.
3661 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, mono_array_size_t *lengths, mono_array_size_t *lower_bounds)
3663 mono_array_size_t byte_len, len, bounds_size;
3669 if (!array_class->inited)
3670 mono_class_init (array_class);
3672 byte_len = mono_array_element_size (array_class);
3675 /* A single dimensional array with a 0 lower bound is the same as an szarray */
3676 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
3678 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
3682 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
3684 for (i = 0; i < array_class->rank; ++i) {
3685 if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
3687 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
3688 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3693 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
3694 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3696 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
3697 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3698 byte_len += sizeof (MonoArray);
3701 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
3702 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3703 byte_len = (byte_len + 3) & ~3;
3704 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
3705 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3706 byte_len += bounds_size;
3709 * Following three lines almost taken from mono_object_new ():
3710 * they need to be kept in sync.
3712 vtable = mono_class_vtable (domain, array_class);
3713 if (!array_class->has_references) {
3714 o = mono_object_allocate_ptrfree (byte_len, vtable);
3715 #if NEED_TO_ZERO_PTRFREE
3716 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
3718 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3719 o = mono_object_allocate_spec (byte_len, vtable);
3721 o = mono_object_allocate (byte_len, vtable);
3724 array = (MonoArray*)o;
3725 array->max_length = len;
3728 MonoArrayBounds *bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
3729 array->bounds = bounds;
3730 for (i = 0; i < array_class->rank; ++i) {
3731 bounds [i].length = lengths [i];
3733 bounds [i].lower_bound = lower_bounds [i];
3737 if (G_UNLIKELY (profile_allocs))
3738 mono_profiler_allocation (o, array_class);
3745 * @domain: domain where the object is created
3746 * @eclass: element class
3747 * @n: number of array elements
3749 * This routine creates a new szarray with @n elements of type @eclass.
3752 mono_array_new (MonoDomain *domain, MonoClass *eclass, mono_array_size_t n)
3756 MONO_ARCH_SAVE_REGS;
3758 ac = mono_array_class_get (eclass, 1);
3761 return mono_array_new_specific (mono_class_vtable (domain, ac), n);
3765 * mono_array_new_specific:
3766 * @vtable: a vtable in the appropriate domain for an initialized class
3767 * @n: number of array elements
3769 * This routine is a fast alternative to mono_array_new() for code which
3770 * can be sure about the domain it operates in.
3773 mono_array_new_specific (MonoVTable *vtable, mono_array_size_t n)
3777 guint32 byte_len, elem_size;
3779 MONO_ARCH_SAVE_REGS;
3781 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
3786 elem_size = mono_array_element_size (vtable->klass);
3787 if (CHECK_MUL_OVERFLOW_UN (n, elem_size)) {
3788 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3791 byte_len = n * elem_size;
3792 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray))) {
3793 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3796 byte_len += sizeof (MonoArray);
3797 if (!vtable->klass->has_references) {
3798 o = mono_object_allocate_ptrfree (byte_len, vtable);
3799 #if NEED_TO_ZERO_PTRFREE
3800 ((MonoArray*)o)->bounds = NULL;
3801 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
3803 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3804 o = mono_object_allocate_spec (byte_len, vtable);
3806 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
3807 o = mono_object_allocate (byte_len, vtable);
3810 ao = (MonoArray *)o;
3812 if (G_UNLIKELY (profile_allocs))
3813 mono_profiler_allocation (o, vtable->klass);
3819 * mono_string_new_utf16:
3820 * @text: a pointer to an utf16 string
3821 * @len: the length of the string
3823 * Returns: A newly created string object which contains @text.
3826 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
3830 s = mono_string_new_size (domain, len);
3831 g_assert (s != NULL);
3833 memcpy (mono_string_chars (s), text, len * 2);
3839 * mono_string_new_size:
3840 * @text: a pointer to an utf16 string
3841 * @len: the length of the string
3843 * Returns: A newly created string object of @len
3846 mono_string_new_size (MonoDomain *domain, gint32 len)
3850 size_t size = (sizeof (MonoString) + ((len + 1) * 2));
3852 /* overflow ? can't fit it, can't allocate it! */
3854 mono_gc_out_of_memory (-1);
3856 vtable = mono_class_vtable (domain, mono_defaults.string_class);
3858 s = mono_object_allocate_ptrfree (size, vtable);
3861 #if NEED_TO_ZERO_PTRFREE
3864 if (G_UNLIKELY (profile_allocs))
3865 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
3871 * mono_string_new_len:
3872 * @text: a pointer to an utf8 string
3873 * @length: number of bytes in @text to consider
3875 * Returns: A newly created string object which contains @text.
3878 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
3880 GError *error = NULL;
3881 MonoString *o = NULL;
3883 glong items_written;
3885 ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
3888 o = mono_string_new_utf16 (domain, ut, items_written);
3890 g_error_free (error);
3899 * @text: a pointer to an utf8 string
3901 * Returns: A newly created string object which contains @text.
3904 mono_string_new (MonoDomain *domain, const char *text)
3906 GError *error = NULL;
3907 MonoString *o = NULL;
3909 glong items_written;
3914 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
3917 o = mono_string_new_utf16 (domain, ut, items_written);
3919 g_error_free (error);
3922 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
3927 MonoString *o = NULL;
3929 if (!g_utf8_validate (text, -1, &end))
3932 len = g_utf8_strlen (text, -1);
3933 o = mono_string_new_size (domain, len);
3934 str = mono_string_chars (o);
3936 while (text < end) {
3937 *str++ = g_utf8_get_char (text);
3938 text = g_utf8_next_char (text);
3945 * mono_string_new_wrapper:
3946 * @text: pointer to utf8 characters.
3948 * Helper function to create a string object from @text in the current domain.
3951 mono_string_new_wrapper (const char *text)
3953 MonoDomain *domain = mono_domain_get ();
3955 MONO_ARCH_SAVE_REGS;
3958 return mono_string_new (domain, text);
3965 * @class: the class of the value
3966 * @value: a pointer to the unboxed data
3968 * Returns: A newly created object which contains @value.
3971 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
3977 g_assert (class->valuetype);
3978 if (mono_class_is_nullable (class))
3979 return mono_nullable_box (value, class);
3981 vtable = mono_class_vtable (domain, class);
3982 size = mono_class_instance_size (class);
3983 res = mono_object_new_alloc_specific (vtable);
3984 if (G_UNLIKELY (profile_allocs))
3985 mono_profiler_allocation (res, class);
3987 size = size - sizeof (MonoObject);
3990 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
3993 #if NO_UNALIGNED_ACCESS
3994 memcpy ((char *)res + sizeof (MonoObject), value, size);
3998 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
4001 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
4004 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
4007 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
4010 memcpy ((char *)res + sizeof (MonoObject), value, size);
4013 if (class->has_finalize)
4014 mono_object_register_finalizer (res);
4020 * @dest: destination pointer
4021 * @src: source pointer
4022 * @klass: a valuetype class
4024 * Copy a valuetype from @src to @dest. This function must be used
4025 * when @klass contains references fields.
4028 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
4030 int size = mono_class_value_size (klass, NULL);
4031 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
4032 memcpy (dest, src, size);
4036 * mono_value_copy_array:
4037 * @dest: destination array
4038 * @dest_idx: index in the @dest array
4039 * @src: source pointer
4040 * @count: number of items
4042 * Copy @count valuetype items from @src to @dest. This function must be used
4043 * when @klass contains references fields.
4044 * Overlap is handled.
4047 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
4049 int size = mono_array_element_size (dest->obj.vtable->klass);
4050 char *d = mono_array_addr_with_size (dest, size, dest_idx);
4051 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
4052 memmove (d, src, size * count);
4056 * mono_object_get_domain:
4057 * @obj: object to query
4059 * Returns: the MonoDomain where the object is hosted
4062 mono_object_get_domain (MonoObject *obj)
4064 return mono_object_domain (obj);
4068 * mono_object_get_class:
4069 * @obj: object to query
4071 * Returns: the MonOClass of the object.
4074 mono_object_get_class (MonoObject *obj)
4076 return mono_object_class (obj);
4079 * mono_object_get_size:
4080 * @o: object to query
4082 * Returns: the size, in bytes, of @o
4085 mono_object_get_size (MonoObject* o)
4087 MonoClass* klass = mono_object_class (o);
4088 if (klass == mono_defaults.string_class) {
4089 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
4090 } else if (o->vtable->rank) {
4091 MonoArray *array = (MonoArray*)o;
4092 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
4093 if (array->bounds) {
4096 size += sizeof (MonoArrayBounds) * o->vtable->rank;
4100 return mono_class_instance_size (klass);
4105 * mono_object_unbox:
4106 * @obj: object to unbox
4108 * Returns: a pointer to the start of the valuetype boxed in this
4111 * This method will assert if the object passed is not a valuetype.
4114 mono_object_unbox (MonoObject *obj)
4116 /* add assert for valuetypes? */
4117 g_assert (obj->vtable->klass->valuetype);
4118 return ((char*)obj) + sizeof (MonoObject);
4122 * mono_object_isinst:
4124 * @klass: a pointer to a class
4126 * Returns: @obj if @obj is derived from @klass
4129 mono_object_isinst (MonoObject *obj, MonoClass *klass)
4132 mono_class_init (klass);
4134 if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE)
4135 return mono_object_isinst_mbyref (obj, klass);
4140 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
4144 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
4153 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4154 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
4158 MonoClass *oklass = vt->klass;
4159 if ((oklass == mono_defaults.transparent_proxy_class))
4160 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
4162 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
4166 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
4168 MonoDomain *domain = mono_domain_get ();
4170 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
4171 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
4172 MonoMethod *im = NULL;
4175 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
4176 im = mono_object_get_virtual_method (rp, im);
4179 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
4182 res = mono_runtime_invoke (im, rp, pa, NULL);
4184 if (*(MonoBoolean *) mono_object_unbox(res)) {
4185 /* Update the vtable of the remote type, so it can safely cast to this new type */
4186 mono_upgrade_remote_class (domain, obj, klass);
4195 * mono_object_castclass_mbyref:
4197 * @klass: a pointer to a class
4199 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
4202 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
4204 if (!obj) return NULL;
4205 if (mono_object_isinst_mbyref (obj, klass)) return obj;
4207 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
4209 "InvalidCastException"));
4214 MonoDomain *orig_domain;
4220 str_lookup (MonoDomain *domain, gpointer user_data)
4222 LDStrInfo *info = user_data;
4223 if (info->res || domain == info->orig_domain)
4225 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
4231 mono_string_get_pinned (MonoString *str)
4235 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
4236 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
4237 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
4238 news->length = mono_string_length (str);
4243 #define mono_string_get_pinned(str) (str)
4247 mono_string_is_interned_lookup (MonoString *str, int insert)
4249 MonoGHashTable *ldstr_table;
4253 domain = ((MonoObject *)str)->vtable->domain;
4254 ldstr_table = domain->ldstr_table;
4256 if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
4261 str = mono_string_get_pinned (str);
4262 mono_g_hash_table_insert (ldstr_table, str, str);
4266 LDStrInfo ldstr_info;
4267 ldstr_info.orig_domain = domain;
4268 ldstr_info.ins = str;
4269 ldstr_info.res = NULL;
4271 mono_domain_foreach (str_lookup, &ldstr_info);
4272 if (ldstr_info.res) {
4274 * the string was already interned in some other domain:
4275 * intern it in the current one as well.
4277 mono_g_hash_table_insert (ldstr_table, str, str);
4287 * mono_string_is_interned:
4288 * @o: String to probe
4290 * Returns whether the string has been interned.
4293 mono_string_is_interned (MonoString *o)
4295 return mono_string_is_interned_lookup (o, FALSE);
4299 * mono_string_intern:
4300 * @o: String to intern
4302 * Interns the string passed.
4303 * Returns: The interned string.
4306 mono_string_intern (MonoString *str)
4308 return mono_string_is_interned_lookup (str, TRUE);
4313 * @domain: the domain where the string will be used.
4314 * @image: a metadata context
4315 * @idx: index into the user string table.
4317 * Implementation for the ldstr opcode.
4318 * Returns: a loaded string from the @image/@idx combination.
4321 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
4323 MONO_ARCH_SAVE_REGS;
4326 return mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
4328 return mono_ldstr_metdata_sig (domain, mono_metadata_user_string (image, idx));
4332 * mono_ldstr_metdata_sig
4333 * @domain: the domain for the string
4334 * @sig: the signature of a metadata string
4336 * Returns: a MonoString for a string stored in the metadata
4339 mono_ldstr_metdata_sig (MonoDomain *domain, const char* sig)
4341 const char *str = sig;
4342 MonoString *o, *interned;
4345 len2 = mono_metadata_decode_blob_size (str, &str);
4348 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
4349 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
4352 guint16 *p2 = (guint16*)mono_string_chars (o);
4353 for (i = 0; i < len2; ++i) {
4354 *p2 = GUINT16_FROM_LE (*p2);
4360 if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
4362 /* o will get garbage collected */
4366 o = mono_string_get_pinned (o);
4367 mono_g_hash_table_insert (domain->ldstr_table, o, o);
4374 * mono_string_to_utf8:
4375 * @s: a System.String
4377 * Return the UTF8 representation for @s.
4378 * the resulting buffer nedds to be freed with g_free().
4381 mono_string_to_utf8 (MonoString *s)
4385 GError *error = NULL;
4391 return g_strdup ("");
4393 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &error);
4395 MonoException *exc = mono_get_exception_argument ("string", error->message);
4396 g_error_free (error);
4397 mono_raise_exception(exc);
4399 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
4400 if (s->length > written) {
4401 /* allocate the total length and copy the part of the string that has been converted */
4402 char *as2 = g_malloc0 (s->length);
4403 memcpy (as2, as, written);
4412 * mono_string_to_utf16:
4415 * Return an null-terminated array of the utf-16 chars
4416 * contained in @s. The result must be freed with g_free().
4417 * This is a temporary helper until our string implementation
4418 * is reworked to always include the null terminating char.
4421 mono_string_to_utf16 (MonoString *s)
4428 as = g_malloc ((s->length * 2) + 2);
4429 as [(s->length * 2)] = '\0';
4430 as [(s->length * 2) + 1] = '\0';
4433 return (gunichar2 *)(as);
4436 memcpy (as, mono_string_chars(s), s->length * 2);
4437 return (gunichar2 *)(as);
4441 * mono_string_from_utf16:
4442 * @data: the UTF16 string (LPWSTR) to convert
4444 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
4446 * Returns: a MonoString.
4449 mono_string_from_utf16 (gunichar2 *data)
4451 MonoDomain *domain = mono_domain_get ();
4457 while (data [len]) len++;
4459 return mono_string_new_utf16 (domain, data, len);
4463 * mono_string_to_utf8_mp:
4464 * @s: a System.String
4466 * Same as mono_string_to_utf8, but allocate the string from a mempool.
4469 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s)
4471 char *r = mono_string_to_utf8 (s);
4478 len = strlen (r) + 1;
4479 mp_s = mono_mempool_alloc (mp, len);
4480 memcpy (mp_s, r, len);
4488 default_ex_handler (MonoException *ex)
4490 MonoObject *o = (MonoObject*)ex;
4491 g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
4495 static MonoExceptionFunc ex_handler = default_ex_handler;
4498 * mono_install_handler:
4499 * @func: exception handler
4501 * This is an internal JIT routine used to install the handler for exceptions
4505 mono_install_handler (MonoExceptionFunc func)
4507 ex_handler = func? func: default_ex_handler;
4511 * mono_raise_exception:
4512 * @ex: exception object
4514 * Signal the runtime that the exception @ex has been raised in unmanaged code.
4517 mono_raise_exception (MonoException *ex)
4520 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
4521 * that will cause gcc to omit the function epilog, causing problems when
4522 * the JIT tries to walk the stack, since the return address on the stack
4523 * will point into the next function in the executable, not this one.
4526 if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class)
4527 MONO_OBJECT_SETREF (mono_thread_current (), abort_exc, ex);
4533 * mono_wait_handle_new:
4534 * @domain: Domain where the object will be created
4535 * @handle: Handle for the wait handle
4537 * Returns: A new MonoWaitHandle created in the given domain for the given handle
4540 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
4542 MonoWaitHandle *res;
4543 gpointer params [1];
4544 static MonoMethod *handle_set;
4546 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.waithandle_class);
4548 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
4550 handle_set = mono_class_get_property_from_name (mono_defaults.waithandle_class, "Handle")->set;
4552 params [0] = &handle;
4553 mono_runtime_invoke (handle_set, res, params, NULL);
4559 mono_wait_handle_get_handle (MonoWaitHandle *handle)
4561 static MonoClassField *f_os_handle;
4562 static MonoClassField *f_safe_handle;
4564 if (!f_os_handle && !f_safe_handle) {
4565 f_os_handle = mono_class_get_field_from_name (mono_defaults.waithandle_class, "os_handle");
4566 f_safe_handle = mono_class_get_field_from_name (mono_defaults.waithandle_class, "safe_wait_handle");
4571 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
4575 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
4581 * mono_async_result_new:
4582 * @domain:domain where the object will be created.
4583 * @handle: wait handle.
4584 * @state: state to pass to AsyncResult
4585 * @data: C closure data.
4587 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
4588 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
4592 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
4594 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
4595 MonoMethod *method = mono_get_context_capture_method ();
4597 /* we must capture the execution context from the original thread */
4599 MONO_OBJECT_SETREF (res, execution_context, mono_runtime_invoke (method, NULL, NULL, NULL));
4600 /* note: result may be null if the flow is suppressed */
4604 MONO_OBJECT_SETREF (res, object_data, object_data);
4605 MONO_OBJECT_SETREF (res, async_state, state);
4607 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
4609 res->sync_completed = FALSE;
4610 res->completed = FALSE;
4616 mono_message_init (MonoDomain *domain,
4617 MonoMethodMessage *this,
4618 MonoReflectionMethod *method,
4619 MonoArray *out_args)
4621 static MonoClass *object_array_klass;
4622 static MonoClass *byte_array_klass;
4623 static MonoClass *string_array_klass;
4624 MonoMethodSignature *sig = mono_method_signature (method->method);
4630 if (!object_array_klass) {
4633 klass = mono_array_class_get (mono_defaults.object_class, 1);
4636 mono_memory_barrier ();
4637 object_array_klass = klass;
4639 klass = mono_array_class_get (mono_defaults.byte_class, 1);
4642 mono_memory_barrier ();
4643 byte_array_klass = klass;
4645 klass = mono_array_class_get (mono_defaults.string_class, 1);
4648 mono_memory_barrier ();
4649 string_array_klass = klass;
4652 MONO_OBJECT_SETREF (this, method, method);
4654 MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
4655 MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
4656 this->async_result = NULL;
4657 this->call_type = CallType_Sync;
4659 names = g_new (char *, sig->param_count);
4660 mono_method_get_param_names (method->method, (const char **) names);
4661 MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
4663 for (i = 0; i < sig->param_count; i++) {
4664 name = mono_string_new (domain, names [i]);
4665 mono_array_setref (this->names, i, name);
4669 for (i = 0, j = 0; i < sig->param_count; i++) {
4670 if (sig->params [i]->byref) {
4672 MonoObject* arg = mono_array_get (out_args, gpointer, j);
4673 mono_array_setref (this->args, i, arg);
4677 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
4681 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
4684 mono_array_set (this->arg_types, guint8, i, arg_type);
4689 * mono_remoting_invoke:
4690 * @real_proxy: pointer to a RealProxy object
4691 * @msg: The MonoMethodMessage to execute
4692 * @exc: used to store exceptions
4693 * @out_args: used to store output arguments
4695 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
4696 * IMessage interface and it is not trivial to extract results from there. So
4697 * we call an helper method PrivateInvoke instead of calling
4698 * RealProxy::Invoke() directly.
4700 * Returns: the result object.
4703 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
4704 MonoObject **exc, MonoArray **out_args)
4706 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
4709 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
4712 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
4714 real_proxy->vtable->domain->private_invoke_method = im;
4717 pa [0] = real_proxy;
4722 return mono_runtime_invoke (im, NULL, pa, exc);
4726 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
4727 MonoObject **exc, MonoArray **out_args)
4729 static MonoClass *object_array_klass;
4732 MonoMethodSignature *sig;
4734 int i, j, outarg_count = 0;
4736 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
4738 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
4739 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
4740 target = tp->rp->unwrapped_server;
4742 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
4746 domain = mono_domain_get ();
4747 method = msg->method->method;
4748 sig = mono_method_signature (method);
4750 for (i = 0; i < sig->param_count; i++) {
4751 if (sig->params [i]->byref)
4755 if (!object_array_klass) {
4758 klass = mono_array_class_get (mono_defaults.object_class, 1);
4761 mono_memory_barrier ();
4762 object_array_klass = klass;
4765 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
4766 *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
4769 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
4771 for (i = 0, j = 0; i < sig->param_count; i++) {
4772 if (sig->params [i]->byref) {
4774 arg = mono_array_get (msg->args, gpointer, i);
4775 mono_array_setref (*out_args, j, arg);
4784 * mono_print_unhandled_exception:
4785 * @exc: The exception
4787 * Prints the unhandled exception.
4790 mono_print_unhandled_exception (MonoObject *exc)
4792 char *message = (char *) "";
4796 gboolean free_message = FALSE;
4798 if (mono_object_isinst (exc, mono_defaults.exception_class)) {
4799 klass = exc->vtable->klass;
4801 while (klass && method == NULL) {
4802 method = mono_class_get_method_from_name_flags (klass, "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
4804 klass = klass->parent;
4809 str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL);
4811 message = mono_string_to_utf8 (str);
4812 free_message = TRUE;
4817 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
4818 * exc->vtable->klass->name, message);
4820 g_printerr ("\nUnhandled Exception: %s\n", message);
4827 * mono_delegate_ctor:
4828 * @this: pointer to an uninitialized delegate object
4829 * @target: target object
4830 * @addr: pointer to native code
4833 * Initialize a delegate and sets a specific method, not the one
4834 * associated with addr. This is useful when sharing generic code.
4835 * In that case addr will most probably not be associated with the
4836 * correct instantiation of the method.
4839 mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer addr, MonoMethod *method)
4841 MonoDelegate *delegate = (MonoDelegate *)this;
4848 delegate->method = method;
4850 class = this->vtable->klass;
4851 mono_stats.delegate_creations++;
4853 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
4855 method = mono_marshal_get_remoting_invoke (method);
4856 delegate->method_ptr = mono_compile_method (method);
4857 MONO_OBJECT_SETREF (delegate, target, target);
4858 } else if (mono_method_signature (method)->hasthis && method->klass->valuetype) {
4859 method = mono_marshal_get_unbox_wrapper (method);
4860 delegate->method_ptr = mono_compile_method (method);
4861 MONO_OBJECT_SETREF (delegate, target, target);
4863 delegate->method_ptr = addr;
4864 MONO_OBJECT_SETREF (delegate, target, target);
4867 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->klass);
4871 * mono_delegate_ctor:
4872 * @this: pointer to an uninitialized delegate object
4873 * @target: target object
4874 * @addr: pointer to native code
4876 * This is used to initialize a delegate.
4879 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
4881 MonoDomain *domain = mono_domain_get ();
4883 MonoMethod *method = NULL;
4887 if ((ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr)))) {
4888 method = ji->method;
4889 g_assert (!method->klass->generic_container);
4892 mono_delegate_ctor_with_method (this, target, addr, method);
4896 * mono_method_call_message_new:
4897 * @method: method to encapsulate
4898 * @params: parameters to the method
4899 * @invoke: optional, delegate invoke.
4900 * @cb: async callback delegate.
4901 * @state: state passed to the async callback.
4903 * Translates arguments pointers into a MonoMethodMessage.
4906 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
4907 MonoDelegate **cb, MonoObject **state)
4909 MonoDomain *domain = mono_domain_get ();
4910 MonoMethodSignature *sig = mono_method_signature (method);
4911 MonoMethodMessage *msg;
4914 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
4917 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
4918 count = sig->param_count - 2;
4920 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
4921 count = sig->param_count;
4924 for (i = 0; i < count; i++) {
4929 if (sig->params [i]->byref)
4930 vpos = *((gpointer *)params [i]);
4934 type = sig->params [i]->type;
4935 class = mono_class_from_mono_type (sig->params [i]);
4937 if (class->valuetype)
4938 arg = mono_value_box (domain, class, vpos);
4940 arg = *((MonoObject **)vpos);
4942 mono_array_setref (msg->args, i, arg);
4945 if (cb != NULL && state != NULL) {
4946 *cb = *((MonoDelegate **)params [i]);
4948 *state = *((MonoObject **)params [i]);
4955 * mono_method_return_message_restore:
4957 * Restore results from message based processing back to arguments pointers
4960 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
4962 MonoMethodSignature *sig = mono_method_signature (method);
4963 int i, j, type, size, out_len;
4965 if (out_args == NULL)
4967 out_len = mono_array_length (out_args);
4971 for (i = 0, j = 0; i < sig->param_count; i++) {
4972 MonoType *pt = sig->params [i];
4977 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
4979 arg = mono_array_get (out_args, gpointer, j);
4983 case MONO_TYPE_VOID:
4984 g_assert_not_reached ();
4988 case MONO_TYPE_BOOLEAN:
4991 case MONO_TYPE_CHAR:
4998 case MONO_TYPE_VALUETYPE: {
5000 size = mono_class_value_size (((MonoObject*)arg)->vtable->klass, NULL);
5001 memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
5004 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
5005 memset (*((gpointer *)params [i]), 0, size);
5009 case MONO_TYPE_STRING:
5010 case MONO_TYPE_CLASS:
5011 case MONO_TYPE_ARRAY:
5012 case MONO_TYPE_SZARRAY:
5013 case MONO_TYPE_OBJECT:
5014 **((MonoObject ***)params [i]) = (MonoObject *)arg;
5017 g_assert_not_reached ();
5026 * mono_load_remote_field:
5027 * @this: pointer to an object
5028 * @klass: klass of the object containing @field
5029 * @field: the field to load
5030 * @res: a storage to store the result
5032 * This method is called by the runtime on attempts to load fields of
5033 * transparent proxy objects. @this points to such TP, @klass is the class of
5034 * the object containing @field. @res is a storage location which can be
5035 * used to store the result.
5037 * Returns: an address pointing to the value of field.
5040 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
5042 static MonoMethod *getter = NULL;
5043 MonoDomain *domain = mono_domain_get ();
5044 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5045 MonoClass *field_class;
5046 MonoMethodMessage *msg;
5047 MonoArray *out_args;
5051 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5052 g_assert (res != NULL);
5054 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5055 mono_field_get_value (tp->rp->unwrapped_server, field, res);
5060 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
5064 field_class = mono_class_from_mono_type (field->type);
5066 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5067 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
5068 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
5070 full_name = mono_type_get_full_name (klass);
5071 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5072 mono_array_setref (msg->args, 1, mono_string_new (domain, field->name));
5075 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5077 if (exc) mono_raise_exception ((MonoException *)exc);
5079 if (mono_array_length (out_args) == 0)
5082 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
5084 if (field_class->valuetype) {
5085 return ((char *)*res) + sizeof (MonoObject);
5091 * mono_load_remote_field_new:
5096 * Missing documentation.
5099 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
5101 static MonoMethod *getter = NULL;
5102 MonoDomain *domain = mono_domain_get ();
5103 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5104 MonoClass *field_class;
5105 MonoMethodMessage *msg;
5106 MonoArray *out_args;
5107 MonoObject *exc, *res;
5110 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5112 field_class = mono_class_from_mono_type (field->type);
5114 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5116 if (field_class->valuetype) {
5117 res = mono_object_new (domain, field_class);
5118 val = ((gchar *) res) + sizeof (MonoObject);
5122 mono_field_get_value (tp->rp->unwrapped_server, field, val);
5127 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
5131 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5132 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
5134 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
5136 full_name = mono_type_get_full_name (klass);
5137 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5138 mono_array_setref (msg->args, 1, mono_string_new (domain, field->name));
5141 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5143 if (exc) mono_raise_exception ((MonoException *)exc);
5145 if (mono_array_length (out_args) == 0)
5148 res = mono_array_get (out_args, MonoObject *, 0);
5154 * mono_store_remote_field:
5155 * @this: pointer to an object
5156 * @klass: klass of the object containing @field
5157 * @field: the field to load
5158 * @val: the value/object to store
5160 * This method is called by the runtime on attempts to store fields of
5161 * transparent proxy objects. @this points to such TP, @klass is the class of
5162 * the object containing @field. @val is the new value to store in @field.
5165 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
5167 static MonoMethod *setter = NULL;
5168 MonoDomain *domain = mono_domain_get ();
5169 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5170 MonoClass *field_class;
5171 MonoMethodMessage *msg;
5172 MonoArray *out_args;
5177 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5179 field_class = mono_class_from_mono_type (field->type);
5181 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5182 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
5183 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
5188 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
5192 if (field_class->valuetype)
5193 arg = mono_value_box (domain, field_class, val);
5195 arg = *((MonoObject **)val);
5198 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5199 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
5201 full_name = mono_type_get_full_name (klass);
5202 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5203 mono_array_setref (msg->args, 1, mono_string_new (domain, field->name));
5204 mono_array_setref (msg->args, 2, arg);
5207 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5209 if (exc) mono_raise_exception ((MonoException *)exc);
5213 * mono_store_remote_field_new:
5219 * Missing documentation
5222 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
5224 static MonoMethod *setter = NULL;
5225 MonoDomain *domain = mono_domain_get ();
5226 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5227 MonoClass *field_class;
5228 MonoMethodMessage *msg;
5229 MonoArray *out_args;
5233 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5235 field_class = mono_class_from_mono_type (field->type);
5237 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5238 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
5239 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
5244 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
5248 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5249 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
5251 full_name = mono_type_get_full_name (klass);
5252 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5253 mono_array_setref (msg->args, 1, mono_string_new (domain, field->name));
5254 mono_array_setref (msg->args, 2, arg);
5257 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5259 if (exc) mono_raise_exception ((MonoException *)exc);
5263 * mono_create_ftnptr:
5265 * Given a function address, create a function descriptor for it.
5266 * This is only needed on IA64 and PPC64.
5269 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
5274 mono_domain_lock (domain);
5275 desc = mono_code_manager_reserve (domain->code_mp, 2 * sizeof (gpointer));
5276 mono_domain_unlock (domain);
5282 #elif defined(__ppc64__) || defined(__powerpc64__)
5285 mono_domain_lock (domain);
5286 desc = mono_code_manager_reserve (domain->code_mp, 3 * sizeof (gpointer));
5287 mono_domain_unlock (domain);
5300 * mono_get_addr_from_ftnptr:
5302 * Given a pointer to a function descriptor, return the function address.
5303 * This is only needed on IA64 and PPC64.
5306 mono_get_addr_from_ftnptr (gpointer descr)
5308 #if defined(__ia64__) || defined(__ppc64__) || defined(__powerpc64__)
5309 return *(gpointer*)descr;
5317 * mono_string_chars:
5320 * Returns a pointer to the UCS16 characters stored in the MonoString
5323 mono_string_chars(MonoString *s)
5325 /* This method is here only for documentation extraction, this is a macro */
5329 * mono_string_length:
5332 * Returns the lenght in characters of the string
5335 mono_string_length (MonoString *s)
5337 /* This method is here only for documentation extraction, this is a macro */