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 return mono_class_create_runtime_vtable (domain, class);
1323 * mono_class_try_get_vtable:
1324 * @domain: the application domain
1325 * @class: the class to initialize
1327 * This function tries to get the associated vtable from @class if
1328 * it was already created.
1331 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *class)
1333 MonoClassRuntimeInfo *runtime_info;
1337 runtime_info = class->runtime_info;
1338 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1339 return runtime_info->domain_vtables [domain->domain_id];
1344 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class)
1347 MonoClassRuntimeInfo *runtime_info, *old_info;
1348 MonoClassField *field;
1351 int imt_table_bytes = 0;
1352 guint32 vtable_size, class_size;
1354 guint32 constant_cols [MONO_CONSTANT_SIZE];
1356 gpointer *interface_offsets;
1358 mono_domain_lock (domain);
1359 runtime_info = class->runtime_info;
1360 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1361 mono_domain_unlock (domain);
1362 return runtime_info->domain_vtables [domain->domain_id];
1364 if (!class->inited || class->exception_type) {
1365 if (!mono_class_init (class) || class->exception_type){
1367 mono_domain_unlock (domain);
1368 exc = mono_class_get_exception_for_failure (class);
1370 mono_raise_exception (exc);
1374 mono_class_init (class);
1377 * For some classes, mono_class_init () already computed class->vtable_size, and
1378 * that is all that is needed because of the vtable trampolines.
1380 if (!class->vtable_size)
1381 mono_class_setup_vtable (class);
1383 if (class->exception_type) {
1384 mono_domain_unlock (domain);
1389 vtable_size = sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
1390 if (class->interface_offsets_count) {
1391 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1392 vtable_size += sizeof (gpointer) * (MONO_IMT_SIZE);
1393 mono_stats.imt_number_of_tables++;
1394 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
1397 vtable_size = sizeof (gpointer) * (class->max_interface_id + 1) +
1398 sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
1401 mono_stats.used_class_count++;
1402 mono_stats.class_vtable_size += vtable_size;
1403 interface_offsets = mono_mempool_alloc0 (domain->mp, vtable_size);
1406 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1408 vt = (MonoVTable*) (interface_offsets + class->max_interface_id + 1);
1410 vt->rank = class->rank;
1411 vt->domain = domain;
1413 mono_class_compute_gc_descriptor (class);
1415 * We can't use typed allocation in the non-root domains, since the
1416 * collector needs the GC descriptor stored in the vtable even after
1417 * the mempool containing the vtable is destroyed when the domain is
1418 * unloaded. An alternative might be to allocate vtables in the GC
1419 * heap, but this does not seem to work (it leads to crashes inside
1420 * libgc). If that approach is tried, two gc descriptors need to be
1421 * allocated for each class: one for the root domain, and one for all
1422 * other domains. The second descriptor should contain a bit for the
1423 * vtable field in MonoObject, since we can no longer assume the
1424 * vtable is reachable by other roots after the appdomain is unloaded.
1426 #ifdef HAVE_BOEHM_GC
1427 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1428 vt->gc_descr = GC_NO_DESCRIPTOR;
1431 vt->gc_descr = class->gc_descr;
1433 if ((class_size = mono_class_data_size (class))) {
1434 if (class->has_static_refs) {
1435 gpointer statics_gc_descr;
1437 gsize default_bitmap [4] = {0};
1440 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1441 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
1442 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set? max_set + 1: 0);
1443 vt->data = mono_gc_alloc_fixed (class_size, statics_gc_descr);
1444 mono_domain_add_class_static_data (domain, class, vt->data, NULL);
1445 if (bitmap != default_bitmap)
1448 vt->data = mono_mempool_alloc0 (domain->mp, class_size);
1450 mono_stats.class_static_data_size += class_size;
1455 while ((field = mono_class_get_fields (class, &iter))) {
1456 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1458 if (mono_field_is_deleted (field))
1460 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1461 gint32 special_static = class->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (class, field);
1462 if (special_static != SPECIAL_STATIC_NONE) {
1463 guint32 size, offset;
1465 size = mono_type_size (field->type, &align);
1466 offset = mono_alloc_special_static_data (special_static, size, align);
1467 if (!domain->special_static_fields)
1468 domain->special_static_fields = g_hash_table_new (NULL, NULL);
1469 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
1473 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
1474 MonoClass *fklass = mono_class_from_mono_type (field->type);
1475 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
1476 t = (char*)vt->data + field->offset;
1477 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
1480 if (fklass->valuetype) {
1481 memcpy (t, field->data, mono_class_value_size (fklass, NULL));
1483 /* it's a pointer type: add check */
1484 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
1485 *t = *(char *)field->data;
1489 if (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT))
1492 /* later do this only on demand if needed */
1494 cindex = mono_metadata_get_constant_index (class->image, mono_class_get_field_token (field), cindex + 1);
1496 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA));
1498 mono_metadata_decode_row (&class->image->tables [MONO_TABLE_CONSTANT], cindex - 1, constant_cols, MONO_CONSTANT_SIZE);
1499 field->def_type = constant_cols [MONO_CONSTANT_TYPE];
1500 field->data = (gpointer)mono_metadata_blob_heap (class->image, constant_cols [MONO_CONSTANT_VALUE]);
1505 vt->max_interface_id = class->max_interface_id;
1506 vt->interface_bitmap = class->interface_bitmap;
1508 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
1509 // class->name, class->interface_offsets_count);
1511 if (! ARCH_USE_IMT) {
1512 /* initialize interface offsets */
1513 for (i = 0; i < class->interface_offsets_count; ++i) {
1514 int interface_id = class->interfaces_packed [i]->interface_id;
1515 int slot = class->interface_offsets_packed [i];
1516 interface_offsets [class->max_interface_id - interface_id] = &(vt->vtable [slot]);
1520 /* FIXME: class_vtable_hash is basically obsolete now: remove as soon
1521 * as we change the code in appdomain.c to invalidate vtables by
1522 * looking at the possible MonoClasses created for the domain.
1524 g_hash_table_insert (domain->class_vtable_hash, class, vt);
1525 /* class->runtime_info is protected by the loader lock, both when
1526 * it it enlarged and when it is stored info.
1528 mono_loader_lock ();
1529 old_info = class->runtime_info;
1530 if (old_info && old_info->max_domain >= domain->domain_id) {
1531 /* someone already created a large enough runtime info */
1532 mono_memory_barrier ();
1533 old_info->domain_vtables [domain->domain_id] = vt;
1535 int new_size = domain->domain_id;
1537 new_size = MAX (new_size, old_info->max_domain);
1539 /* make the new size a power of two */
1541 while (new_size > i)
1544 /* this is a bounded memory retention issue: may want to
1545 * handle it differently when we'll have a rcu-like system.
1547 runtime_info = mono_mempool_alloc0 (class->image->mempool, sizeof (MonoClassRuntimeInfo) + new_size * sizeof (gpointer));
1548 runtime_info->max_domain = new_size - 1;
1549 /* copy the stuff from the older info */
1551 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
1553 runtime_info->domain_vtables [domain->domain_id] = vt;
1555 mono_memory_barrier ();
1556 class->runtime_info = runtime_info;
1558 mono_loader_unlock ();
1560 /* Initialize vtable */
1561 if (vtable_trampoline) {
1562 // This also covers the AOT case
1563 for (i = 0; i < class->vtable_size; ++i) {
1564 vt->vtable [i] = vtable_trampoline;
1567 mono_class_setup_vtable (class);
1569 for (i = 0; i < class->vtable_size; ++i) {
1572 if ((cm = class->vtable [i])) {
1573 if (mono_method_signature (cm)->generic_param_count)
1574 /* FIXME: Why is this needed ? */
1575 vt->vtable [i] = cm;
1577 vt->vtable [i] = vtable_trampoline? vtable_trampoline: arch_create_jit_trampoline (cm);
1582 if (ARCH_USE_IMT && imt_table_bytes) {
1583 /* Now that the vtable is full, we can actually fill up the IMT */
1584 if (imt_trampoline) {
1585 /* lazy construction of the IMT entries enabled */
1586 for (i = 0; i < MONO_IMT_SIZE; ++i)
1587 interface_offsets [i] = imt_trampoline;
1589 build_imt (class, vt, domain, interface_offsets, NULL);
1593 mono_domain_unlock (domain);
1595 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
1596 if (mono_is_security_manager_active () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND)) {
1597 MonoException *exc = mono_class_get_exception_for_failure (class);
1599 mono_raise_exception (exc);
1602 /* make sure the parent is initialized */
1604 mono_class_vtable (domain, class->parent);
1606 vt->type = mono_type_get_object (domain, &class->byval_arg);
1607 if (class->contextbound)
1616 * mono_class_proxy_vtable:
1617 * @domain: the application domain
1618 * @remove_class: the remote class
1620 * Creates a vtable for transparent proxies. It is basically
1621 * a copy of the real vtable of the class wrapped in @remote_class,
1622 * but all function pointers invoke the remoting functions, and
1623 * vtable->klass points to the transparent proxy class, and not to @class.
1626 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
1628 MonoVTable *vt, *pvt;
1629 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
1631 GSList *extra_interfaces = NULL;
1632 MonoClass *class = remote_class->proxy_class;
1633 gpointer *interface_offsets;
1635 vt = mono_class_vtable (domain, class);
1636 max_interface_id = vt->max_interface_id;
1638 /* Calculate vtable space for extra interfaces */
1639 for (j = 0; j < remote_class->interface_count; j++) {
1640 MonoClass* iclass = remote_class->interfaces[j];
1644 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
1645 continue; /* interface implemented by the class */
1646 if (g_slist_find (extra_interfaces, iclass))
1649 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
1651 method_count = mono_class_num_methods (iclass);
1653 ifaces = mono_class_get_implemented_interfaces (iclass);
1655 for (i = 0; i < ifaces->len; ++i) {
1656 MonoClass *ic = g_ptr_array_index (ifaces, i);
1657 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
1658 continue; /* interface implemented by the class */
1659 if (g_slist_find (extra_interfaces, ic))
1661 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
1662 method_count += mono_class_num_methods (ic);
1664 g_ptr_array_free (ifaces, TRUE);
1667 extra_interface_vtsize += method_count * sizeof (gpointer);
1668 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
1672 mono_stats.imt_number_of_tables++;
1673 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
1674 vtsize = sizeof (gpointer) * (MONO_IMT_SIZE) +
1675 sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
1677 vtsize = sizeof (gpointer) * (max_interface_id + 1) +
1678 sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
1681 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
1683 interface_offsets = mono_mempool_alloc0 (domain->mp, vtsize + extra_interface_vtsize);
1685 pvt = (MonoVTable*) (interface_offsets + MONO_IMT_SIZE);
1687 pvt = (MonoVTable*) (interface_offsets + max_interface_id + 1);
1688 memcpy (pvt, vt, sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer));
1690 pvt->klass = mono_defaults.transparent_proxy_class;
1691 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
1692 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
1694 /* initialize vtable */
1695 mono_class_setup_vtable (class);
1696 for (i = 0; i < class->vtable_size; ++i) {
1699 if ((cm = class->vtable [i]))
1700 pvt->vtable [i] = mono_method_signature (cm)->generic_param_count
1701 ? cm : arch_create_remoting_trampoline (cm, target_type);
1703 pvt->vtable [i] = NULL;
1706 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
1707 /* create trampolines for abstract methods */
1708 for (k = class; k; k = k->parent) {
1710 gpointer iter = NULL;
1711 while ((m = mono_class_get_methods (k, &iter)))
1712 if (!pvt->vtable [m->slot])
1713 pvt->vtable [m->slot] = mono_method_signature (m)->generic_param_count ? m : arch_create_remoting_trampoline (m, target_type);
1717 pvt->max_interface_id = max_interface_id;
1718 pvt->interface_bitmap = mono_mempool_alloc0 (domain->mp, sizeof (guint8) * (max_interface_id/8 + 1 ));
1720 if (! ARCH_USE_IMT) {
1721 /* initialize interface offsets */
1722 for (i = 0; i < class->interface_offsets_count; ++i) {
1723 int interface_id = class->interfaces_packed [i]->interface_id;
1724 int slot = class->interface_offsets_packed [i];
1725 interface_offsets [class->max_interface_id - interface_id] = &(pvt->vtable [slot]);
1728 for (i = 0; i < class->interface_offsets_count; ++i) {
1729 int interface_id = class->interfaces_packed [i]->interface_id;
1730 pvt->interface_bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
1733 if (extra_interfaces) {
1734 int slot = class->vtable_size;
1740 /* Create trampolines for the methods of the interfaces */
1741 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1742 interf = list_item->data;
1744 if (! ARCH_USE_IMT) {
1745 interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
1747 pvt->interface_bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
1751 while ((cm = mono_class_get_methods (interf, &iter)))
1752 pvt->vtable [slot + j++] = mono_method_signature (cm)->generic_param_count ? cm : arch_create_remoting_trampoline (cm, target_type);
1754 slot += mono_class_num_methods (interf);
1756 if (! ARCH_USE_IMT) {
1757 g_slist_free (extra_interfaces);
1762 /* Now that the vtable is full, we can actually fill up the IMT */
1763 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
1764 if (extra_interfaces) {
1765 g_slist_free (extra_interfaces);
1773 * mono_class_field_is_special_static:
1775 * Returns whether @field is a thread/context static field.
1778 mono_class_field_is_special_static (MonoClassField *field)
1780 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1782 if (mono_field_is_deleted (field))
1784 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1785 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
1792 * mono_class_has_special_static_fields:
1794 * Returns whenever @klass has any thread/context static fields.
1797 mono_class_has_special_static_fields (MonoClass *klass)
1799 MonoClassField *field;
1803 while ((field = mono_class_get_fields (klass, &iter))) {
1804 g_assert (field->parent == klass);
1805 if (mono_class_field_is_special_static (field))
1813 * create_remote_class_key:
1814 * Creates an array of pointers that can be used as a hash key for a remote class.
1815 * The first element of the array is the number of pointers.
1818 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
1823 if (remote_class == NULL) {
1824 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1825 key = g_malloc (sizeof(gpointer) * 3);
1826 key [0] = GINT_TO_POINTER (2);
1827 key [1] = mono_defaults.marshalbyrefobject_class;
1828 key [2] = extra_class;
1830 key = g_malloc (sizeof(gpointer) * 2);
1831 key [0] = GINT_TO_POINTER (1);
1832 key [1] = extra_class;
1835 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
1836 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
1837 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
1838 key [1] = remote_class->proxy_class;
1840 // Keep the list of interfaces sorted
1841 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
1842 if (extra_class && remote_class->interfaces [i] > extra_class) {
1843 key [j++] = extra_class;
1846 key [j] = remote_class->interfaces [i];
1849 key [j] = extra_class;
1851 // Replace the old class. The interface list is the same
1852 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
1853 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
1854 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
1855 for (i = 0; i < remote_class->interface_count; i++)
1856 key [2 + i] = remote_class->interfaces [i];
1864 * copy_remote_class_key:
1866 * Make a copy of KEY in the mempool MP and return the copy.
1869 copy_remote_class_key (MonoMemPool *mp, gpointer *key)
1871 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
1872 gpointer *mp_key = mono_mempool_alloc (mp, key_size);
1874 memcpy (mp_key, key, key_size);
1880 * mono_remote_class:
1881 * @domain: the application domain
1882 * @class_name: name of the remote class
1884 * Creates and initializes a MonoRemoteClass object for a remote type.
1888 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
1890 MonoRemoteClass *rc;
1891 gpointer* key, *mp_key;
1893 key = create_remote_class_key (NULL, proxy_class);
1895 mono_domain_lock (domain);
1896 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
1900 mono_domain_unlock (domain);
1904 mp_key = copy_remote_class_key (domain->mp, key);
1908 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1909 rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass) + sizeof(MonoClass*));
1910 rc->interface_count = 1;
1911 rc->interfaces [0] = proxy_class;
1912 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
1914 rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass));
1915 rc->interface_count = 0;
1916 rc->proxy_class = proxy_class;
1919 rc->default_vtable = NULL;
1920 rc->xdomain_vtable = NULL;
1921 rc->proxy_class_name = mono_string_to_utf8_mp (domain->mp, class_name);
1923 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
1925 mono_domain_unlock (domain);
1930 * clone_remote_class:
1931 * Creates a copy of the remote_class, adding the provided class or interface
1933 static MonoRemoteClass*
1934 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
1936 MonoRemoteClass *rc;
1937 gpointer* key, *mp_key;
1939 key = create_remote_class_key (remote_class, extra_class);
1940 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
1946 mp_key = copy_remote_class_key (domain->mp, key);
1950 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1952 rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass) + sizeof(MonoClass*) * (remote_class->interface_count + 1));
1953 rc->proxy_class = remote_class->proxy_class;
1954 rc->interface_count = remote_class->interface_count + 1;
1956 // Keep the list of interfaces sorted, since the hash key of
1957 // the remote class depends on this
1958 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
1959 if (remote_class->interfaces [i] > extra_class && i == j)
1960 rc->interfaces [j++] = extra_class;
1961 rc->interfaces [j] = remote_class->interfaces [i];
1964 rc->interfaces [j] = extra_class;
1966 // Replace the old class. The interface array is the same
1967 rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass) + sizeof(MonoClass*) * remote_class->interface_count);
1968 rc->proxy_class = extra_class;
1969 rc->interface_count = remote_class->interface_count;
1970 if (rc->interface_count > 0)
1971 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
1974 rc->default_vtable = NULL;
1975 rc->xdomain_vtable = NULL;
1976 rc->proxy_class_name = remote_class->proxy_class_name;
1978 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
1984 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
1986 mono_domain_lock (domain);
1987 if (rp->target_domain_id != -1) {
1988 if (remote_class->xdomain_vtable == NULL)
1989 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
1990 mono_domain_unlock (domain);
1991 return remote_class->xdomain_vtable;
1993 if (remote_class->default_vtable == NULL) {
1996 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
1997 klass = mono_class_from_mono_type (type);
1998 if ((klass->is_com_object || (mono_defaults.com_object_class && klass == mono_defaults.com_object_class)) && !mono_class_vtable (mono_domain_get (), klass)->remote)
1999 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2001 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2004 mono_domain_unlock (domain);
2005 return remote_class->default_vtable;
2009 * mono_upgrade_remote_class:
2010 * @domain: the application domain
2011 * @tproxy: the proxy whose remote class has to be upgraded.
2012 * @klass: class to which the remote class can be casted.
2014 * Updates the vtable of the remote class by adding the necessary method slots
2015 * and interface offsets so it can be safely casted to klass. klass can be a
2016 * class or an interface.
2019 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2021 MonoTransparentProxy *tproxy;
2022 MonoRemoteClass *remote_class;
2023 gboolean redo_vtable;
2025 mono_domain_lock (domain);
2027 tproxy = (MonoTransparentProxy*) proxy_object;
2028 remote_class = tproxy->remote_class;
2030 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2033 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2034 if (remote_class->interfaces [i] == klass)
2035 redo_vtable = FALSE;
2038 redo_vtable = (remote_class->proxy_class != klass);
2042 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2043 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2046 mono_domain_unlock (domain);
2051 * mono_object_get_virtual_method:
2052 * @obj: object to operate on.
2055 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2056 * the instance of a callvirt of method.
2059 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2062 MonoMethod **vtable;
2064 MonoMethod *res = NULL;
2066 klass = mono_object_class (obj);
2067 if (klass == mono_defaults.transparent_proxy_class) {
2068 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2074 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2077 mono_class_setup_vtable (klass);
2078 vtable = klass->vtable;
2080 /* check method->slot is a valid index: perform isinstance? */
2081 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2083 res = vtable [mono_class_interface_offset (klass, method->klass) + method->slot];
2085 if (method->slot != -1) {
2086 res = vtable [method->slot];
2088 /* method->slot might not be set for instances of generic methods in the AOT case */
2089 if (method->is_inflated) {
2090 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2091 res = vtable [((MonoMethodInflated*)method)->declaring->slot];
2097 /* It may be an interface, abstract class method or generic method */
2098 if (!res || mono_method_signature (res)->generic_param_count)
2101 /* generic methods demand invoke_with_check */
2102 if (mono_method_signature (res)->generic_param_count)
2103 res = mono_marshal_get_remoting_invoke_with_check (res);
2105 res = mono_marshal_get_remoting_invoke (res);
2107 if (method->is_inflated && !res->is_inflated) {
2108 /* Have to inflate the result */
2109 res = mono_class_inflate_generic_method (res, &((MonoMethodInflated*)method)->context);
2119 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2121 g_error ("runtime invoke called on uninitialized runtime");
2125 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2128 * mono_runtime_invoke:
2129 * @method: method to invoke
2130 * @obJ: object instance
2131 * @params: arguments to the method
2132 * @exc: exception information.
2134 * Invokes the method represented by @method on the object @obj.
2136 * obj is the 'this' pointer, it should be NULL for static
2137 * methods, a MonoObject* for object instances and a pointer to
2138 * the value type for value types.
2140 * The params array contains the arguments to the method with the
2141 * same convention: MonoObject* pointers for object instances and
2142 * pointers to the value type otherwise.
2144 * From unmanaged code you'll usually use the
2145 * mono_runtime_invoke() variant.
2147 * Note that this function doesn't handle virtual methods for
2148 * you, it will exec the exact method you pass: we still need to
2149 * expose a function to lookup the derived class implementation
2150 * of a virtual method (there are examples of this in the code,
2153 * You can pass NULL as the exc argument if you don't want to
2154 * catch exceptions, otherwise, *exc will be set to the exception
2155 * thrown, if any. if an exception is thrown, you can't use the
2156 * MonoObject* result from the function.
2158 * If the method returns a value type, it is boxed in an object
2162 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2164 return default_mono_runtime_invoke (method, obj, params, exc);
2168 * mono_method_get_unmanaged_thunk:
2169 * @method: method to generate a thunk for.
2171 * Returns an unmanaged->managed thunk that can be used to call
2172 * a managed method directly from C.
2174 * The thunk's C signature closely matches the managed signature:
2176 * C#: public bool Equals (object obj);
2177 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2178 * MonoObject*, MonoException**);
2180 * The 1st ("this") parameter must not be used with static methods:
2182 * C#: public static bool ReferenceEquals (object a, object b);
2183 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2186 * The last argument must be a non-null pointer of a MonoException* pointer.
2187 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2188 * exception has been thrown in managed code. Otherwise it will point
2189 * to the MonoException* caught by the thunk. In this case, the result of
2190 * the thunk is undefined:
2192 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2193 * MonoException *ex = NULL;
2194 * Equals func = mono_method_get_unmanaged_thunk (method);
2195 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2197 * // handle exception
2200 * The calling convention of the thunk matches the platform's default
2201 * convention. This means that under Windows, C declarations must
2202 * contain the __stdcall attribute:
2204 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2205 * MonoObject*, MonoException**);
2209 * Value type arguments and return values are treated as they were objects:
2211 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2212 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2214 * Arguments must be properly boxed upon trunk's invocation, while return
2215 * values must be unboxed.
2218 mono_method_get_unmanaged_thunk (MonoMethod *method)
2220 method = mono_marshal_get_thunk_invoke_wrapper (method);
2221 return mono_compile_method (method);
2225 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
2229 gpointer *p = (gpointer*)dest;
2236 case MONO_TYPE_BOOLEAN:
2238 case MONO_TYPE_U1: {
2239 guint8 *p = (guint8*)dest;
2240 *p = value ? *(guint8*)value : 0;
2245 case MONO_TYPE_CHAR: {
2246 guint16 *p = (guint16*)dest;
2247 *p = value ? *(guint16*)value : 0;
2250 #if SIZEOF_VOID_P == 4
2255 case MONO_TYPE_U4: {
2256 gint32 *p = (gint32*)dest;
2257 *p = value ? *(gint32*)value : 0;
2260 #if SIZEOF_VOID_P == 8
2265 case MONO_TYPE_U8: {
2266 gint64 *p = (gint64*)dest;
2267 *p = value ? *(gint64*)value : 0;
2270 case MONO_TYPE_R4: {
2271 float *p = (float*)dest;
2272 *p = value ? *(float*)value : 0;
2275 case MONO_TYPE_R8: {
2276 double *p = (double*)dest;
2277 *p = value ? *(double*)value : 0;
2280 case MONO_TYPE_STRING:
2281 case MONO_TYPE_SZARRAY:
2282 case MONO_TYPE_CLASS:
2283 case MONO_TYPE_OBJECT:
2284 case MONO_TYPE_ARRAY:
2285 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2287 case MONO_TYPE_FNPTR:
2288 case MONO_TYPE_PTR: {
2289 gpointer *p = (gpointer*)dest;
2290 *p = deref_pointer? *(gpointer*)value: value;
2293 case MONO_TYPE_VALUETYPE:
2294 /* note that 't' and 'type->type' can be different */
2295 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
2296 t = type->data.klass->enum_basetype->type;
2300 size = mono_class_value_size (mono_class_from_mono_type (type), NULL);
2302 memset (dest, 0, size);
2304 memcpy (dest, value, size);
2307 case MONO_TYPE_GENERICINST:
2308 t = type->data.generic_class->container_class->byval_arg.type;
2311 g_warning ("got type %x", type->type);
2312 g_assert_not_reached ();
2317 * mono_field_set_value:
2318 * @obj: Instance object
2319 * @field: MonoClassField describing the field to set
2320 * @value: The value to be set
2322 * Sets the value of the field described by @field in the object instance @obj
2323 * to the value passed in @value. This method should only be used for instance
2324 * fields. For static fields, use mono_field_static_set_value.
2326 * The value must be on the native format of the field type.
2329 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
2333 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2335 dest = (char*)obj + field->offset;
2336 set_value (field->type, dest, value, FALSE);
2340 * mono_field_static_set_value:
2341 * @field: MonoClassField describing the field to set
2342 * @value: The value to be set
2344 * Sets the value of the static field described by @field
2345 * to the value passed in @value.
2347 * The value must be on the native format of the field type.
2350 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
2354 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2355 /* you cant set a constant! */
2356 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
2358 dest = (char*)vt->data + field->offset;
2359 set_value (field->type, dest, value, FALSE);
2362 /* Used by the debugger */
2364 mono_vtable_get_static_field_data (MonoVTable *vt)
2370 * mono_field_get_value:
2371 * @obj: Object instance
2372 * @field: MonoClassField describing the field to fetch information from
2373 * @value: pointer to the location where the value will be stored
2375 * Use this routine to get the value of the field @field in the object
2378 * The pointer provided by value must be of the field type, for reference
2379 * types this is a MonoObject*, for value types its the actual pointer to
2384 * mono_field_get_value (obj, int_field, &i);
2387 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
2391 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2393 src = (char*)obj + field->offset;
2394 set_value (field->type, value, src, TRUE);
2398 * mono_field_get_value_object:
2399 * @domain: domain where the object will be created (if boxing)
2400 * @field: MonoClassField describing the field to fetch information from
2401 * @obj: The object instance for the field.
2403 * Returns: a new MonoObject with the value from the given field. If the
2404 * field represents a value type, the value is boxed.
2408 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
2412 MonoVTable *vtable = NULL;
2414 gboolean is_static = FALSE;
2415 gboolean is_ref = FALSE;
2417 switch (field->type->type) {
2418 case MONO_TYPE_STRING:
2419 case MONO_TYPE_OBJECT:
2420 case MONO_TYPE_CLASS:
2421 case MONO_TYPE_ARRAY:
2422 case MONO_TYPE_SZARRAY:
2427 case MONO_TYPE_BOOLEAN:
2430 case MONO_TYPE_CHAR:
2439 case MONO_TYPE_VALUETYPE:
2440 is_ref = field->type->byref;
2442 case MONO_TYPE_GENERICINST:
2443 is_ref = !field->type->data.generic_class->container_class->valuetype;
2446 g_error ("type 0x%x not handled in "
2447 "mono_field_get_value_object", field->type->type);
2451 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
2453 vtable = mono_class_vtable (domain, field->parent);
2454 if (!vtable->initialized)
2455 mono_runtime_class_init (vtable);
2460 mono_field_static_get_value (vtable, field, &o);
2462 mono_field_get_value (obj, field, &o);
2467 /* boxed value type */
2468 klass = mono_class_from_mono_type (field->type);
2469 o = mono_object_new (domain, klass);
2470 v = ((gchar *) o) + sizeof (MonoObject);
2472 mono_field_static_get_value (vtable, field, v);
2474 mono_field_get_value (obj, field, v);
2481 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
2484 const char *p = blob;
2485 mono_metadata_decode_blob_size (p, &p);
2488 case MONO_TYPE_BOOLEAN:
2491 *(guint8 *) value = *p;
2493 case MONO_TYPE_CHAR:
2496 *(guint16*) value = read16 (p);
2500 *(guint32*) value = read32 (p);
2504 *(guint64*) value = read64 (p);
2507 readr4 (p, (float*) value);
2510 readr8 (p, (double*) value);
2512 case MONO_TYPE_STRING:
2513 *(gpointer*) value = mono_ldstr_metdata_sig (domain, blob);
2515 case MONO_TYPE_CLASS:
2516 *(gpointer*) value = NULL;
2520 g_warning ("type 0x%02x should not be in constant table", type);
2526 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
2528 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT);
2529 mono_get_constant_value_from_blob (domain, field->def_type, field->data, value);
2533 * mono_field_static_get_value:
2534 * @vt: vtable to the object
2535 * @field: MonoClassField describing the field to fetch information from
2536 * @value: where the value is returned
2538 * Use this routine to get the value of the static field @field value.
2540 * The pointer provided by value must be of the field type, for reference
2541 * types this is a MonoObject*, for value types its the actual pointer to
2546 * mono_field_static_get_value (vt, int_field, &i);
2549 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
2553 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2555 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
2556 get_default_field_value (vt->domain, field, value);
2560 src = (char*)vt->data + field->offset;
2561 set_value (field->type, value, src, TRUE);
2565 * mono_property_set_value:
2566 * @prop: MonoProperty to set
2567 * @obj: instance object on which to act
2568 * @params: parameters to pass to the propery
2569 * @exc: optional exception
2571 * Invokes the property's set method with the given arguments on the
2572 * object instance obj (or NULL for static properties).
2574 * You can pass NULL as the exc argument if you don't want to
2575 * catch exceptions, otherwise, *exc will be set to the exception
2576 * thrown, if any. if an exception is thrown, you can't use the
2577 * MonoObject* result from the function.
2580 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
2582 default_mono_runtime_invoke (prop->set, obj, params, exc);
2586 * mono_property_get_value:
2587 * @prop: MonoProperty to fetch
2588 * @obj: instance object on which to act
2589 * @params: parameters to pass to the propery
2590 * @exc: optional exception
2592 * Invokes the property's get method with the given arguments on the
2593 * object instance obj (or NULL for static properties).
2595 * You can pass NULL as the exc argument if you don't want to
2596 * catch exceptions, otherwise, *exc will be set to the exception
2597 * thrown, if any. if an exception is thrown, you can't use the
2598 * MonoObject* result from the function.
2600 * Returns: the value from invoking the get method on the property.
2603 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
2605 return default_mono_runtime_invoke (prop->get, obj, params, exc);
2609 * mono_nullable_init:
2610 * @buf: The nullable structure to initialize.
2611 * @value: the value to initialize from
2612 * @klass: the type for the object
2614 * Initialize the nullable structure pointed to by @buf from @value which
2615 * should be a boxed value type. The size of @buf should be able to hold
2616 * as much data as the @klass->instance_size (which is the number of bytes
2617 * that will be copies).
2619 * Since Nullables have variable structure, we can not define a C
2620 * structure for them.
2623 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
2625 MonoClass *param_class = klass->cast_class;
2627 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
2628 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
2630 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
2632 memcpy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
2634 memset (buf + klass->fields [0].offset - sizeof (MonoObject), 0, mono_class_value_size (param_class, NULL));
2638 * mono_nullable_box:
2639 * @buf: The buffer representing the data to be boxed
2640 * @klass: the type to box it as.
2642 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
2646 mono_nullable_box (guint8 *buf, MonoClass *klass)
2648 MonoClass *param_class = klass->cast_class;
2650 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
2651 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
2653 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
2654 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
2655 memcpy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
2663 * mono_get_delegate_invoke:
2664 * @klass: The delegate class
2666 * Returns: the MonoMethod for the "Invoke" method in the delegate klass
2669 mono_get_delegate_invoke (MonoClass *klass)
2673 im = mono_class_get_method_from_name (klass, "Invoke", -1);
2680 * mono_runtime_delegate_invoke:
2681 * @delegate: pointer to a delegate object.
2682 * @params: parameters for the delegate.
2683 * @exc: Pointer to the exception result.
2685 * Invokes the delegate method @delegate with the parameters provided.
2687 * You can pass NULL as the exc argument if you don't want to
2688 * catch exceptions, otherwise, *exc will be set to the exception
2689 * thrown, if any. if an exception is thrown, you can't use the
2690 * MonoObject* result from the function.
2693 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
2697 im = mono_get_delegate_invoke (delegate->vtable->klass);
2700 return mono_runtime_invoke (im, delegate, params, exc);
2703 static char **main_args = NULL;
2704 static int num_main_args;
2707 * mono_runtime_get_main_args:
2709 * Returns: a MonoArray with the arguments passed to the main program
2712 mono_runtime_get_main_args (void)
2716 MonoDomain *domain = mono_domain_get ();
2721 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
2723 for (i = 0; i < num_main_args; ++i)
2724 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
2730 fire_process_exit_event (void)
2732 MonoClassField *field;
2733 MonoDomain *domain = mono_domain_get ();
2735 MonoObject *delegate, *exc;
2737 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "ProcessExit");
2740 if (domain != mono_get_root_domain ())
2743 delegate = *(MonoObject **)(((char *)domain->domain) + field->offset);
2744 if (delegate == NULL)
2749 mono_runtime_delegate_invoke (delegate, pa, &exc);
2753 * mono_runtime_run_main:
2754 * @method: the method to start the application with (usually Main)
2755 * @argc: number of arguments from the command line
2756 * @argv: array of strings from the command line
2757 * @exc: excetption results
2759 * Execute a standard Main() method (argc/argv contains the
2760 * executable name). This method also sets the command line argument value
2761 * needed by System.Environment.
2766 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
2770 MonoArray *args = NULL;
2771 MonoDomain *domain = mono_domain_get ();
2772 gchar *utf8_fullpath;
2775 g_assert (method != NULL);
2777 mono_thread_set_main (mono_thread_current ());
2779 main_args = g_new0 (char*, argc);
2780 num_main_args = argc;
2782 if (!g_path_is_absolute (argv [0])) {
2783 gchar *basename = g_path_get_basename (argv [0]);
2784 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
2788 utf8_fullpath = mono_utf8_from_external (fullpath);
2789 if(utf8_fullpath == NULL) {
2790 /* Printing the arg text will cause glib to
2791 * whinge about "Invalid UTF-8", but at least
2792 * its relevant, and shows the problem text
2795 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
2796 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
2803 utf8_fullpath = mono_utf8_from_external (argv[0]);
2804 if(utf8_fullpath == NULL) {
2805 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
2806 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
2811 main_args [0] = utf8_fullpath;
2813 for (i = 1; i < argc; ++i) {
2816 utf8_arg=mono_utf8_from_external (argv[i]);
2817 if(utf8_arg==NULL) {
2818 /* Ditto the comment about Invalid UTF-8 here */
2819 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
2820 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
2824 main_args [i] = utf8_arg;
2828 if (mono_method_signature (method)->param_count) {
2829 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
2830 for (i = 0; i < argc; ++i) {
2831 /* The encodings should all work, given that
2832 * we've checked all these args for the
2835 gchar *str = mono_utf8_from_external (argv [i]);
2836 MonoString *arg = mono_string_new (domain, str);
2837 mono_array_setref (args, i, arg);
2841 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
2844 mono_assembly_set_main (method->klass->image->assembly);
2846 result = mono_runtime_exec_main (method, args, exc);
2847 fire_process_exit_event ();
2851 /* Used in call_unhandled_exception_delegate */
2853 create_unhandled_exception_eventargs (MonoObject *exc)
2857 MonoMethod *method = NULL;
2858 MonoBoolean is_terminating = TRUE;
2861 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
2864 mono_class_init (klass);
2866 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
2867 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
2871 args [1] = &is_terminating;
2873 obj = mono_object_new (mono_domain_get (), klass);
2874 mono_runtime_invoke (method, obj, args, NULL);
2879 /* Used in mono_unhandled_exception */
2881 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
2882 MonoObject *e = NULL;
2885 pa [0] = domain->domain;
2886 pa [1] = create_unhandled_exception_eventargs (exc);
2887 mono_runtime_delegate_invoke (delegate, pa, &e);
2890 gchar *msg = mono_string_to_utf8 (((MonoException *) e)->message);
2891 g_warning ("exception inside UnhandledException handler: %s\n", msg);
2896 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANLED_POLICY_CURRENT;
2899 * mono_runtime_unhandled_exception_policy_set:
2900 * @policy: the new policy
2902 * This is a VM internal routine.
2904 * Sets the runtime policy for handling unhandled exceptions.
2907 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
2908 runtime_unhandled_exception_policy = policy;
2912 * mono_runtime_unhandled_exception_policy_get:
2914 * This is a VM internal routine.
2916 * Gets the runtime policy for handling unhandled exceptions.
2918 MonoRuntimeUnhandledExceptionPolicy
2919 mono_runtime_unhandled_exception_policy_get (void) {
2920 return runtime_unhandled_exception_policy;
2924 * mono_unhandled_exception:
2925 * @exc: exception thrown
2927 * This is a VM internal routine.
2929 * We call this function when we detect an unhandled exception
2930 * in the default domain.
2932 * It invokes the * UnhandledException event in AppDomain or prints
2933 * a warning to the console
2936 mono_unhandled_exception (MonoObject *exc)
2938 MonoDomain *current_domain = mono_domain_get ();
2939 MonoDomain *root_domain = mono_get_root_domain ();
2940 MonoClassField *field;
2941 MonoObject *current_appdomain_delegate;
2942 MonoObject *root_appdomain_delegate;
2944 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
2945 "UnhandledException");
2948 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
2949 gboolean abort_process = (mono_thread_current () == main_thread) ||
2950 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANLED_POLICY_CURRENT);
2951 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
2952 if (current_domain != root_domain && (mono_get_runtime_info ()->framework_version [0] >= '2')) {
2953 current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
2955 current_appdomain_delegate = NULL;
2958 /* set exitcode only if we will abort the process */
2960 mono_environment_exitcode_set (1);
2961 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
2962 mono_print_unhandled_exception (exc);
2964 if (root_appdomain_delegate) {
2965 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
2967 if (current_appdomain_delegate) {
2968 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
2975 * Launch a new thread to execute a function
2977 * main_func is called back from the thread with main_args as the
2978 * parameter. The callback function is expected to start Main()
2979 * eventually. This function then waits for all managed threads to
2981 * It is not necesseray anymore to execute managed code in a subthread,
2982 * so this function should not be used anymore by default: just
2983 * execute the code and then call mono_thread_manage ().
2986 mono_runtime_exec_managed_code (MonoDomain *domain,
2987 MonoMainThreadFunc main_func,
2990 mono_thread_create (domain, main_func, main_args);
2992 mono_thread_manage ();
2996 * Execute a standard Main() method (args doesn't contain the
3000 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
3005 MonoCustomAttrInfo* cinfo;
3006 gboolean has_stathread_attribute;
3007 MonoThread* thread = mono_thread_current ();
3013 domain = mono_object_domain (args);
3014 if (!domain->entry_assembly) {
3016 MonoAssembly *assembly;
3018 assembly = method->klass->image->assembly;
3019 domain->entry_assembly = assembly;
3020 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
3022 str = g_strconcat (assembly->image->name, ".config", NULL);
3023 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
3027 cinfo = mono_custom_attrs_from_method (method);
3029 static MonoClass *stathread_attribute = NULL;
3030 if (!stathread_attribute)
3031 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
3032 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
3034 mono_custom_attrs_free (cinfo);
3036 has_stathread_attribute = FALSE;
3038 if (has_stathread_attribute) {
3039 thread->apartment_state = ThreadApartmentState_STA;
3040 } else if (mono_get_runtime_info ()->framework_version [0] == '1') {
3041 thread->apartment_state = ThreadApartmentState_Unknown;
3043 thread->apartment_state = ThreadApartmentState_MTA;
3045 mono_thread_init_apartment_state ();
3047 mono_debugger_event (MONO_DEBUGGER_EVENT_REACHED_MAIN, 0, 0);
3049 /* FIXME: check signature of method */
3050 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
3052 res = mono_runtime_invoke (method, NULL, pa, exc);
3054 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
3058 mono_environment_exitcode_set (rval);
3060 mono_runtime_invoke (method, NULL, pa, exc);
3064 /* If the return type of Main is void, only
3065 * set the exitcode if an exception was thrown
3066 * (we don't want to blow away an
3067 * explicitly-set exit code)
3070 mono_environment_exitcode_set (rval);
3074 mono_debugger_event (MONO_DEBUGGER_EVENT_MAIN_EXITED, (guint64) (gsize) rval, 0);
3080 * mono_install_runtime_invoke:
3081 * @func: Function to install
3083 * This is a VM internal routine
3086 mono_install_runtime_invoke (MonoInvokeFunc func)
3088 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
3093 * mono_runtime_invoke_array:
3094 * @method: method to invoke
3095 * @obJ: object instance
3096 * @params: arguments to the method
3097 * @exc: exception information.
3099 * Invokes the method represented by @method on the object @obj.
3101 * obj is the 'this' pointer, it should be NULL for static
3102 * methods, a MonoObject* for object instances and a pointer to
3103 * the value type for value types.
3105 * The params array contains the arguments to the method with the
3106 * same convention: MonoObject* pointers for object instances and
3107 * pointers to the value type otherwise. The _invoke_array
3108 * variant takes a C# object[] as the params argument (MonoArray
3109 * *params): in this case the value types are boxed inside the
3110 * respective reference representation.
3112 * From unmanaged code you'll usually use the
3113 * mono_runtime_invoke() variant.
3115 * Note that this function doesn't handle virtual methods for
3116 * you, it will exec the exact method you pass: we still need to
3117 * expose a function to lookup the derived class implementation
3118 * of a virtual method (there are examples of this in the code,
3121 * You can pass NULL as the exc argument if you don't want to
3122 * catch exceptions, otherwise, *exc will be set to the exception
3123 * thrown, if any. if an exception is thrown, you can't use the
3124 * MonoObject* result from the function.
3126 * If the method returns a value type, it is boxed in an object
3130 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
3133 MonoMethodSignature *sig = mono_method_signature (method);
3134 gpointer *pa = NULL;
3137 if (NULL != params) {
3138 pa = alloca (sizeof (gpointer) * mono_array_length (params));
3139 for (i = 0; i < mono_array_length (params); i++) {
3140 MonoType *t = sig->params [i];
3146 case MONO_TYPE_BOOLEAN:
3149 case MONO_TYPE_CHAR:
3158 case MONO_TYPE_VALUETYPE:
3159 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
3162 g_assert_not_reached ();
3163 /* The runtime invoke wrapper needs the original boxed vtype */
3164 pa [i] = mono_array_get (params, MonoObject*, i);
3166 /* MS seems to create the objects if a null is passed in */
3167 if (!mono_array_get (params, MonoObject*, i))
3168 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
3172 * We can't pass the unboxed vtype byref to the callee, since
3173 * that would mean the callee would be able to modify boxed
3174 * primitive types. So we (and MS) make a copy of the boxed
3175 * object, pass that to the callee, and replace the original
3176 * boxed object in the arg array with the copy.
3178 MonoObject *orig = mono_array_get (params, MonoObject*, i);
3179 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
3180 mono_array_setref (params, i, copy);
3183 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
3186 case MONO_TYPE_STRING:
3187 case MONO_TYPE_OBJECT:
3188 case MONO_TYPE_CLASS:
3189 case MONO_TYPE_ARRAY:
3190 case MONO_TYPE_SZARRAY:
3192 pa [i] = mono_array_addr (params, MonoObject*, i);
3193 // FIXME: I need to check this code path
3195 pa [i] = mono_array_get (params, MonoObject*, i);
3197 case MONO_TYPE_GENERICINST:
3199 t = &t->data.generic_class->container_class->this_arg;
3201 t = &t->data.generic_class->container_class->byval_arg;
3204 g_error ("type 0x%x not handled in ves_icall_InternalInvoke", sig->params [i]->type);
3209 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
3212 if (mono_class_is_nullable (method->klass)) {
3213 /* Need to create a boxed vtype instead */
3219 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
3223 obj = mono_object_new (mono_domain_get (), method->klass);
3224 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
3225 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
3227 if (method->klass->valuetype)
3228 o = mono_object_unbox (obj);
3231 } else if (method->klass->valuetype) {
3232 obj = mono_value_box (mono_domain_get (), method->klass, obj);
3235 mono_runtime_invoke (method, o, pa, exc);
3238 if (mono_class_is_nullable (method->klass)) {
3239 MonoObject *nullable;
3241 /* Convert the unboxed vtype into a Nullable structure */
3242 nullable = mono_object_new (mono_domain_get (), method->klass);
3244 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
3245 obj = mono_object_unbox (nullable);
3248 /* obj must be already unboxed if needed */
3249 return mono_runtime_invoke (method, obj, pa, exc);
3254 arith_overflow (void)
3256 mono_raise_exception (mono_get_exception_overflow ());
3260 * mono_object_allocate:
3261 * @size: number of bytes to allocate
3263 * This is a very simplistic routine until we have our GC-aware
3266 * Returns: an allocated object of size @size, or NULL on failure.
3268 static inline void *
3269 mono_object_allocate (size_t size, MonoVTable *vtable)
3272 mono_stats.new_object_count++;
3273 ALLOC_OBJECT (o, vtable, size);
3279 * mono_object_allocate_ptrfree:
3280 * @size: number of bytes to allocate
3282 * Note that the memory allocated is not zeroed.
3283 * Returns: an allocated object of size @size, or NULL on failure.
3285 static inline void *
3286 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
3289 mono_stats.new_object_count++;
3290 ALLOC_PTRFREE (o, vtable, size);
3294 static inline void *
3295 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
3298 ALLOC_TYPED (o, size, vtable);
3299 mono_stats.new_object_count++;
3306 * @klass: the class of the object that we want to create
3308 * Returns: a newly created object whose definition is
3309 * looked up using @klass. This will not invoke any constructors,
3310 * so the consumer of this routine has to invoke any constructors on
3311 * its own to initialize the object.
3314 mono_object_new (MonoDomain *domain, MonoClass *klass)
3316 MONO_ARCH_SAVE_REGS;
3317 return mono_object_new_specific (mono_class_vtable (domain, klass));
3321 * mono_object_new_specific:
3322 * @vtable: the vtable of the object that we want to create
3324 * Returns: A newly created object with class and domain specified
3328 mono_object_new_specific (MonoVTable *vtable)
3332 MONO_ARCH_SAVE_REGS;
3334 /* check for is_com_object for COM Interop */
3335 if (vtable->remote || vtable->klass->is_com_object)
3338 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
3341 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
3344 mono_class_init (klass);
3346 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
3348 vtable->domain->create_proxy_for_type_method = im;
3351 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
3353 o = mono_runtime_invoke (im, NULL, pa, NULL);
3354 if (o != NULL) return o;
3357 return mono_object_new_alloc_specific (vtable);
3361 mono_object_new_alloc_specific (MonoVTable *vtable)
3365 if (!vtable->klass->has_references) {
3366 o = mono_object_new_ptrfree (vtable);
3367 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3368 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
3370 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
3371 o = mono_object_allocate (vtable->klass->instance_size, vtable);
3373 if (G_UNLIKELY (vtable->klass->has_finalize))
3374 mono_object_register_finalizer (o);
3376 if (G_UNLIKELY (profile_allocs))
3377 mono_profiler_allocation (o, vtable->klass);
3382 mono_object_new_fast (MonoVTable *vtable)
3385 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
3390 mono_object_new_ptrfree (MonoVTable *vtable)
3393 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
3394 #if NEED_TO_ZERO_PTRFREE
3395 /* an inline memset is much faster for the common vcase of small objects
3396 * note we assume the allocated size is a multiple of sizeof (void*).
3398 if (vtable->klass->instance_size < 128) {
3400 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
3401 p = (gpointer*)((char*)obj + sizeof (MonoObject));
3407 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
3414 mono_object_new_ptrfree_box (MonoVTable *vtable)
3417 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
3418 /* the object will be boxed right away, no need to memzero it */
3423 * mono_class_get_allocation_ftn:
3425 * @for_box: the object will be used for boxing
3426 * @pass_size_in_words:
3428 * Return the allocation function appropriate for the given class.
3432 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
3434 *pass_size_in_words = FALSE;
3436 if (!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
3437 profile_allocs = FALSE;
3439 if (vtable->klass->has_finalize || vtable->klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
3440 return mono_object_new_specific;
3442 if (!vtable->klass->has_references) {
3443 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
3445 return mono_object_new_ptrfree_box;
3446 return mono_object_new_ptrfree;
3449 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3451 return mono_object_new_fast;
3454 * FIXME: This is actually slower than mono_object_new_fast, because
3455 * of the overhead of parameter passing.
3458 *pass_size_in_words = TRUE;
3459 #ifdef GC_REDIRECT_TO_LOCAL
3460 return GC_local_gcj_fast_malloc;
3462 return GC_gcj_fast_malloc;
3467 return mono_object_new_specific;
3471 * mono_object_new_from_token:
3472 * @image: Context where the type_token is hosted
3473 * @token: a token of the type that we want to create
3475 * Returns: A newly created object whose definition is
3476 * looked up using @token in the @image image
3479 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
3483 class = mono_class_get (image, token);
3485 return mono_object_new (domain, class);
3490 * mono_object_clone:
3491 * @obj: the object to clone
3493 * Returns: A newly created object who is a shallow copy of @obj
3496 mono_object_clone (MonoObject *obj)
3501 size = obj->vtable->klass->instance_size;
3502 o = mono_object_allocate (size, obj->vtable);
3503 /* do not copy the sync state */
3504 memcpy ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
3507 if (obj->vtable->klass->has_references)
3508 mono_gc_wbarrier_object (o);
3510 if (G_UNLIKELY (profile_allocs))
3511 mono_profiler_allocation (o, obj->vtable->klass);
3513 if (obj->vtable->klass->has_finalize)
3514 mono_object_register_finalizer (o);
3519 * mono_array_full_copy:
3520 * @src: source array to copy
3521 * @dest: destination array
3523 * Copies the content of one array to another with exactly the same type and size.
3526 mono_array_full_copy (MonoArray *src, MonoArray *dest)
3528 mono_array_size_t size;
3529 MonoClass *klass = src->obj.vtable->klass;
3531 MONO_ARCH_SAVE_REGS;
3533 g_assert (klass == dest->obj.vtable->klass);
3535 size = mono_array_length (src);
3536 g_assert (size == mono_array_length (dest));
3537 size *= mono_array_element_size (klass);
3539 if (klass->element_class->valuetype) {
3540 if (klass->element_class->has_references)
3541 mono_value_copy_array (dest, 0, src, mono_array_length (src));
3543 memcpy (&dest->vector, &src->vector, size);
3545 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
3548 memcpy (&dest->vector, &src->vector, size);
3553 * mono_array_clone_in_domain:
3554 * @domain: the domain in which the array will be cloned into
3555 * @array: the array to clone
3557 * This routine returns a copy of the array that is hosted on the
3558 * specified MonoDomain.
3561 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
3564 mono_array_size_t size, i;
3565 mono_array_size_t *sizes;
3566 MonoClass *klass = array->obj.vtable->klass;
3568 MONO_ARCH_SAVE_REGS;
3570 if (array->bounds == NULL) {
3571 size = mono_array_length (array);
3572 o = mono_array_new_full (domain, klass, &size, NULL);
3574 size *= mono_array_element_size (klass);
3576 if (klass->element_class->valuetype) {
3577 if (klass->element_class->has_references)
3578 mono_value_copy_array (o, 0, array, mono_array_length (array));
3580 memcpy (&o->vector, &array->vector, size);
3582 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
3585 memcpy (&o->vector, &array->vector, size);
3590 sizes = alloca (klass->rank * sizeof(mono_array_size_t) * 2);
3591 size = mono_array_element_size (klass);
3592 for (i = 0; i < klass->rank; ++i) {
3593 sizes [i] = array->bounds [i].length;
3594 size *= array->bounds [i].length;
3595 sizes [i + klass->rank] = array->bounds [i].lower_bound;
3597 o = mono_array_new_full (domain, klass, sizes, sizes + klass->rank);
3599 if (klass->element_class->valuetype) {
3600 if (klass->element_class->has_references)
3601 mono_value_copy_array (o, 0, array, mono_array_length (array));
3603 memcpy (&o->vector, &array->vector, size);
3605 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
3608 memcpy (&o->vector, &array->vector, size);
3616 * @array: the array to clone
3618 * Returns: A newly created array who is a shallow copy of @array
3621 mono_array_clone (MonoArray *array)
3623 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
3626 /* helper macros to check for overflow when calculating the size of arrays */
3627 #ifdef MONO_BIG_ARRAYS
3628 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
3629 #define MYGUINT_MAX MYGUINT64_MAX
3630 #define CHECK_ADD_OVERFLOW_UN(a,b) \
3631 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a))
3632 #define CHECK_MUL_OVERFLOW_UN(a,b) \
3633 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
3634 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
3636 #define MYGUINT32_MAX 4294967295U
3637 #define MYGUINT_MAX MYGUINT32_MAX
3638 #define CHECK_ADD_OVERFLOW_UN(a,b) \
3639 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
3640 #define CHECK_MUL_OVERFLOW_UN(a,b) \
3641 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
3642 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
3646 * mono_array_new_full:
3647 * @domain: domain where the object is created
3648 * @array_class: array class
3649 * @lengths: lengths for each dimension in the array
3650 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
3652 * This routine creates a new array objects with the given dimensions,
3653 * lower bounds and type.
3656 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, mono_array_size_t *lengths, mono_array_size_t *lower_bounds)
3658 mono_array_size_t byte_len, len, bounds_size;
3664 if (!array_class->inited)
3665 mono_class_init (array_class);
3667 byte_len = mono_array_element_size (array_class);
3670 /* A single dimensional array with a 0 lower bound is the same as an szarray */
3671 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
3673 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
3677 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
3679 for (i = 0; i < array_class->rank; ++i) {
3680 if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
3682 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
3683 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3688 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
3689 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3691 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
3692 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3693 byte_len += sizeof (MonoArray);
3696 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
3697 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3698 byte_len = (byte_len + 3) & ~3;
3699 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
3700 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3701 byte_len += bounds_size;
3704 * Following three lines almost taken from mono_object_new ():
3705 * they need to be kept in sync.
3707 vtable = mono_class_vtable (domain, array_class);
3708 if (!array_class->has_references) {
3709 o = mono_object_allocate_ptrfree (byte_len, vtable);
3710 #if NEED_TO_ZERO_PTRFREE
3711 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
3713 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3714 o = mono_object_allocate_spec (byte_len, vtable);
3716 o = mono_object_allocate (byte_len, vtable);
3719 array = (MonoArray*)o;
3720 array->max_length = len;
3723 MonoArrayBounds *bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
3724 array->bounds = bounds;
3725 for (i = 0; i < array_class->rank; ++i) {
3726 bounds [i].length = lengths [i];
3728 bounds [i].lower_bound = lower_bounds [i];
3732 if (G_UNLIKELY (profile_allocs))
3733 mono_profiler_allocation (o, array_class);
3740 * @domain: domain where the object is created
3741 * @eclass: element class
3742 * @n: number of array elements
3744 * This routine creates a new szarray with @n elements of type @eclass.
3747 mono_array_new (MonoDomain *domain, MonoClass *eclass, mono_array_size_t n)
3751 MONO_ARCH_SAVE_REGS;
3753 ac = mono_array_class_get (eclass, 1);
3756 return mono_array_new_specific (mono_class_vtable (domain, ac), n);
3760 * mono_array_new_specific:
3761 * @vtable: a vtable in the appropriate domain for an initialized class
3762 * @n: number of array elements
3764 * This routine is a fast alternative to mono_array_new() for code which
3765 * can be sure about the domain it operates in.
3768 mono_array_new_specific (MonoVTable *vtable, mono_array_size_t n)
3772 guint32 byte_len, elem_size;
3774 MONO_ARCH_SAVE_REGS;
3776 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
3781 elem_size = mono_array_element_size (vtable->klass);
3782 if (CHECK_MUL_OVERFLOW_UN (n, elem_size)) {
3783 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3786 byte_len = n * elem_size;
3787 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray))) {
3788 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3791 byte_len += sizeof (MonoArray);
3792 if (!vtable->klass->has_references) {
3793 o = mono_object_allocate_ptrfree (byte_len, vtable);
3794 #if NEED_TO_ZERO_PTRFREE
3795 ((MonoArray*)o)->bounds = NULL;
3796 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
3798 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3799 o = mono_object_allocate_spec (byte_len, vtable);
3801 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
3802 o = mono_object_allocate (byte_len, vtable);
3805 ao = (MonoArray *)o;
3807 if (G_UNLIKELY (profile_allocs))
3808 mono_profiler_allocation (o, vtable->klass);
3814 * mono_string_new_utf16:
3815 * @text: a pointer to an utf16 string
3816 * @len: the length of the string
3818 * Returns: A newly created string object which contains @text.
3821 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
3825 s = mono_string_new_size (domain, len);
3826 g_assert (s != NULL);
3828 memcpy (mono_string_chars (s), text, len * 2);
3834 * mono_string_new_size:
3835 * @text: a pointer to an utf16 string
3836 * @len: the length of the string
3838 * Returns: A newly created string object of @len
3841 mono_string_new_size (MonoDomain *domain, gint32 len)
3845 size_t size = (sizeof (MonoString) + ((len + 1) * 2));
3847 /* overflow ? can't fit it, can't allocate it! */
3849 mono_gc_out_of_memory (-1);
3851 vtable = mono_class_vtable (domain, mono_defaults.string_class);
3853 s = mono_object_allocate_ptrfree (size, vtable);
3856 #if NEED_TO_ZERO_PTRFREE
3859 if (G_UNLIKELY (profile_allocs))
3860 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
3866 * mono_string_new_len:
3867 * @text: a pointer to an utf8 string
3868 * @length: number of bytes in @text to consider
3870 * Returns: A newly created string object which contains @text.
3873 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
3875 GError *error = NULL;
3876 MonoString *o = NULL;
3878 glong items_written;
3880 ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
3883 o = mono_string_new_utf16 (domain, ut, items_written);
3885 g_error_free (error);
3894 * @text: a pointer to an utf8 string
3896 * Returns: A newly created string object which contains @text.
3899 mono_string_new (MonoDomain *domain, const char *text)
3901 GError *error = NULL;
3902 MonoString *o = NULL;
3904 glong items_written;
3909 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
3912 o = mono_string_new_utf16 (domain, ut, items_written);
3914 g_error_free (error);
3917 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
3922 MonoString *o = NULL;
3924 if (!g_utf8_validate (text, -1, &end))
3927 len = g_utf8_strlen (text, -1);
3928 o = mono_string_new_size (domain, len);
3929 str = mono_string_chars (o);
3931 while (text < end) {
3932 *str++ = g_utf8_get_char (text);
3933 text = g_utf8_next_char (text);
3940 * mono_string_new_wrapper:
3941 * @text: pointer to utf8 characters.
3943 * Helper function to create a string object from @text in the current domain.
3946 mono_string_new_wrapper (const char *text)
3948 MonoDomain *domain = mono_domain_get ();
3950 MONO_ARCH_SAVE_REGS;
3953 return mono_string_new (domain, text);
3960 * @class: the class of the value
3961 * @value: a pointer to the unboxed data
3963 * Returns: A newly created object which contains @value.
3966 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
3972 g_assert (class->valuetype);
3973 if (mono_class_is_nullable (class))
3974 return mono_nullable_box (value, class);
3976 vtable = mono_class_vtable (domain, class);
3977 size = mono_class_instance_size (class);
3978 res = mono_object_new_alloc_specific (vtable);
3979 if (G_UNLIKELY (profile_allocs))
3980 mono_profiler_allocation (res, class);
3982 size = size - sizeof (MonoObject);
3985 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
3988 #if NO_UNALIGNED_ACCESS
3989 memcpy ((char *)res + sizeof (MonoObject), value, size);
3993 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
3996 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
3999 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
4002 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
4005 memcpy ((char *)res + sizeof (MonoObject), value, size);
4008 if (class->has_finalize)
4009 mono_object_register_finalizer (res);
4015 * @dest: destination pointer
4016 * @src: source pointer
4017 * @klass: a valuetype class
4019 * Copy a valuetype from @src to @dest. This function must be used
4020 * when @klass contains references fields.
4023 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
4025 int size = mono_class_value_size (klass, NULL);
4026 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
4027 memcpy (dest, src, size);
4031 * mono_value_copy_array:
4032 * @dest: destination array
4033 * @dest_idx: index in the @dest array
4034 * @src: source pointer
4035 * @count: number of items
4037 * Copy @count valuetype items from @src to @dest. This function must be used
4038 * when @klass contains references fields.
4039 * Overlap is handled.
4042 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
4044 int size = mono_array_element_size (dest->obj.vtable->klass);
4045 char *d = mono_array_addr_with_size (dest, size, dest_idx);
4046 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
4047 memmove (d, src, size * count);
4051 * mono_object_get_domain:
4052 * @obj: object to query
4054 * Returns: the MonoDomain where the object is hosted
4057 mono_object_get_domain (MonoObject *obj)
4059 return mono_object_domain (obj);
4063 * mono_object_get_class:
4064 * @obj: object to query
4066 * Returns: the MonOClass of the object.
4069 mono_object_get_class (MonoObject *obj)
4071 return mono_object_class (obj);
4074 * mono_object_get_size:
4075 * @o: object to query
4077 * Returns: the size, in bytes, of @o
4080 mono_object_get_size (MonoObject* o)
4082 MonoClass* klass = mono_object_class (o);
4083 if (klass == mono_defaults.string_class) {
4084 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
4085 } else if (o->vtable->rank) {
4086 MonoArray *array = (MonoArray*)o;
4087 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
4088 if (array->bounds) {
4091 size += sizeof (MonoArrayBounds) * o->vtable->rank;
4095 return mono_class_instance_size (klass);
4100 * mono_object_unbox:
4101 * @obj: object to unbox
4103 * Returns: a pointer to the start of the valuetype boxed in this
4106 * This method will assert if the object passed is not a valuetype.
4109 mono_object_unbox (MonoObject *obj)
4111 /* add assert for valuetypes? */
4112 g_assert (obj->vtable->klass->valuetype);
4113 return ((char*)obj) + sizeof (MonoObject);
4117 * mono_object_isinst:
4119 * @klass: a pointer to a class
4121 * Returns: @obj if @obj is derived from @klass
4124 mono_object_isinst (MonoObject *obj, MonoClass *klass)
4127 mono_class_init (klass);
4129 if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE)
4130 return mono_object_isinst_mbyref (obj, klass);
4135 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
4139 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
4148 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4149 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
4153 MonoClass *oklass = vt->klass;
4154 if ((oklass == mono_defaults.transparent_proxy_class))
4155 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
4157 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
4161 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
4163 MonoDomain *domain = mono_domain_get ();
4165 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
4166 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
4167 MonoMethod *im = NULL;
4170 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
4171 im = mono_object_get_virtual_method (rp, im);
4174 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
4177 res = mono_runtime_invoke (im, rp, pa, NULL);
4179 if (*(MonoBoolean *) mono_object_unbox(res)) {
4180 /* Update the vtable of the remote type, so it can safely cast to this new type */
4181 mono_upgrade_remote_class (domain, obj, klass);
4190 * mono_object_castclass_mbyref:
4192 * @klass: a pointer to a class
4194 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
4197 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
4199 if (!obj) return NULL;
4200 if (mono_object_isinst_mbyref (obj, klass)) return obj;
4202 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
4204 "InvalidCastException"));
4209 MonoDomain *orig_domain;
4215 str_lookup (MonoDomain *domain, gpointer user_data)
4217 LDStrInfo *info = user_data;
4218 if (info->res || domain == info->orig_domain)
4220 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
4226 mono_string_get_pinned (MonoString *str)
4230 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
4231 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
4232 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
4233 news->length = mono_string_length (str);
4238 #define mono_string_get_pinned(str) (str)
4242 mono_string_is_interned_lookup (MonoString *str, int insert)
4244 MonoGHashTable *ldstr_table;
4248 domain = ((MonoObject *)str)->vtable->domain;
4249 ldstr_table = domain->ldstr_table;
4251 if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
4256 str = mono_string_get_pinned (str);
4257 mono_g_hash_table_insert (ldstr_table, str, str);
4261 LDStrInfo ldstr_info;
4262 ldstr_info.orig_domain = domain;
4263 ldstr_info.ins = str;
4264 ldstr_info.res = NULL;
4266 mono_domain_foreach (str_lookup, &ldstr_info);
4267 if (ldstr_info.res) {
4269 * the string was already interned in some other domain:
4270 * intern it in the current one as well.
4272 mono_g_hash_table_insert (ldstr_table, str, str);
4282 * mono_string_is_interned:
4283 * @o: String to probe
4285 * Returns whether the string has been interned.
4288 mono_string_is_interned (MonoString *o)
4290 return mono_string_is_interned_lookup (o, FALSE);
4294 * mono_string_intern:
4295 * @o: String to intern
4297 * Interns the string passed.
4298 * Returns: The interned string.
4301 mono_string_intern (MonoString *str)
4303 return mono_string_is_interned_lookup (str, TRUE);
4308 * @domain: the domain where the string will be used.
4309 * @image: a metadata context
4310 * @idx: index into the user string table.
4312 * Implementation for the ldstr opcode.
4313 * Returns: a loaded string from the @image/@idx combination.
4316 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
4318 MONO_ARCH_SAVE_REGS;
4321 return mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
4323 return mono_ldstr_metdata_sig (domain, mono_metadata_user_string (image, idx));
4327 * mono_ldstr_metdata_sig
4328 * @domain: the domain for the string
4329 * @sig: the signature of a metadata string
4331 * Returns: a MonoString for a string stored in the metadata
4334 mono_ldstr_metdata_sig (MonoDomain *domain, const char* sig)
4336 const char *str = sig;
4337 MonoString *o, *interned;
4340 len2 = mono_metadata_decode_blob_size (str, &str);
4343 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
4344 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
4347 guint16 *p2 = (guint16*)mono_string_chars (o);
4348 for (i = 0; i < len2; ++i) {
4349 *p2 = GUINT16_FROM_LE (*p2);
4355 if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
4357 /* o will get garbage collected */
4361 o = mono_string_get_pinned (o);
4362 mono_g_hash_table_insert (domain->ldstr_table, o, o);
4369 * mono_string_to_utf8:
4370 * @s: a System.String
4372 * Return the UTF8 representation for @s.
4373 * the resulting buffer nedds to be freed with g_free().
4376 mono_string_to_utf8 (MonoString *s)
4380 GError *error = NULL;
4386 return g_strdup ("");
4388 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &error);
4390 MonoException *exc = mono_get_exception_argument ("string", error->message);
4391 g_error_free (error);
4392 mono_raise_exception(exc);
4394 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
4395 if (s->length > written) {
4396 /* allocate the total length and copy the part of the string that has been converted */
4397 char *as2 = g_malloc0 (s->length);
4398 memcpy (as2, as, written);
4407 * mono_string_to_utf16:
4410 * Return an null-terminated array of the utf-16 chars
4411 * contained in @s. The result must be freed with g_free().
4412 * This is a temporary helper until our string implementation
4413 * is reworked to always include the null terminating char.
4416 mono_string_to_utf16 (MonoString *s)
4423 as = g_malloc ((s->length * 2) + 2);
4424 as [(s->length * 2)] = '\0';
4425 as [(s->length * 2) + 1] = '\0';
4428 return (gunichar2 *)(as);
4431 memcpy (as, mono_string_chars(s), s->length * 2);
4432 return (gunichar2 *)(as);
4436 * mono_string_from_utf16:
4437 * @data: the UTF16 string (LPWSTR) to convert
4439 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
4441 * Returns: a MonoString.
4444 mono_string_from_utf16 (gunichar2 *data)
4446 MonoDomain *domain = mono_domain_get ();
4452 while (data [len]) len++;
4454 return mono_string_new_utf16 (domain, data, len);
4458 * mono_string_to_utf8_mp:
4459 * @s: a System.String
4461 * Same as mono_string_to_utf8, but allocate the string from a mempool.
4464 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s)
4466 char *r = mono_string_to_utf8 (s);
4473 len = strlen (r) + 1;
4474 mp_s = mono_mempool_alloc (mp, len);
4475 memcpy (mp_s, r, len);
4483 default_ex_handler (MonoException *ex)
4485 MonoObject *o = (MonoObject*)ex;
4486 g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
4490 static MonoExceptionFunc ex_handler = default_ex_handler;
4493 * mono_install_handler:
4494 * @func: exception handler
4496 * This is an internal JIT routine used to install the handler for exceptions
4500 mono_install_handler (MonoExceptionFunc func)
4502 ex_handler = func? func: default_ex_handler;
4506 * mono_raise_exception:
4507 * @ex: exception object
4509 * Signal the runtime that the exception @ex has been raised in unmanaged code.
4512 mono_raise_exception (MonoException *ex)
4515 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
4516 * that will cause gcc to omit the function epilog, causing problems when
4517 * the JIT tries to walk the stack, since the return address on the stack
4518 * will point into the next function in the executable, not this one.
4521 if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class)
4522 MONO_OBJECT_SETREF (mono_thread_current (), abort_exc, ex);
4528 * mono_wait_handle_new:
4529 * @domain: Domain where the object will be created
4530 * @handle: Handle for the wait handle
4532 * Returns: A new MonoWaitHandle created in the given domain for the given handle
4535 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
4537 MonoWaitHandle *res;
4538 gpointer params [1];
4539 static MonoMethod *handle_set;
4541 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.waithandle_class);
4543 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
4545 handle_set = mono_class_get_property_from_name (mono_defaults.waithandle_class, "Handle")->set;
4547 params [0] = &handle;
4548 mono_runtime_invoke (handle_set, res, params, NULL);
4554 mono_wait_handle_get_handle (MonoWaitHandle *handle)
4556 static MonoClassField *f_os_handle;
4557 static MonoClassField *f_safe_handle;
4559 if (!f_os_handle && !f_safe_handle) {
4560 f_os_handle = mono_class_get_field_from_name (mono_defaults.waithandle_class, "os_handle");
4561 f_safe_handle = mono_class_get_field_from_name (mono_defaults.waithandle_class, "safe_wait_handle");
4566 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
4570 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
4576 * mono_async_result_new:
4577 * @domain:domain where the object will be created.
4578 * @handle: wait handle.
4579 * @state: state to pass to AsyncResult
4580 * @data: C closure data.
4582 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
4583 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
4587 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
4589 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
4590 MonoMethod *method = mono_get_context_capture_method ();
4592 /* we must capture the execution context from the original thread */
4594 MONO_OBJECT_SETREF (res, execution_context, mono_runtime_invoke (method, NULL, NULL, NULL));
4595 /* note: result may be null if the flow is suppressed */
4599 MONO_OBJECT_SETREF (res, object_data, object_data);
4600 MONO_OBJECT_SETREF (res, async_state, state);
4602 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
4604 res->sync_completed = FALSE;
4605 res->completed = FALSE;
4611 mono_message_init (MonoDomain *domain,
4612 MonoMethodMessage *this,
4613 MonoReflectionMethod *method,
4614 MonoArray *out_args)
4616 static MonoClass *object_array_klass;
4617 static MonoClass *byte_array_klass;
4618 static MonoClass *string_array_klass;
4619 MonoMethodSignature *sig = mono_method_signature (method->method);
4625 if (!object_array_klass) {
4628 klass = mono_array_class_get (mono_defaults.object_class, 1);
4631 mono_memory_barrier ();
4632 object_array_klass = klass;
4634 klass = mono_array_class_get (mono_defaults.byte_class, 1);
4637 mono_memory_barrier ();
4638 byte_array_klass = klass;
4640 klass = mono_array_class_get (mono_defaults.string_class, 1);
4643 mono_memory_barrier ();
4644 string_array_klass = klass;
4647 MONO_OBJECT_SETREF (this, method, method);
4649 MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
4650 MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
4651 this->async_result = NULL;
4652 this->call_type = CallType_Sync;
4654 names = g_new (char *, sig->param_count);
4655 mono_method_get_param_names (method->method, (const char **) names);
4656 MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
4658 for (i = 0; i < sig->param_count; i++) {
4659 name = mono_string_new (domain, names [i]);
4660 mono_array_setref (this->names, i, name);
4664 for (i = 0, j = 0; i < sig->param_count; i++) {
4665 if (sig->params [i]->byref) {
4667 MonoObject* arg = mono_array_get (out_args, gpointer, j);
4668 mono_array_setref (this->args, i, arg);
4672 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
4676 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
4679 mono_array_set (this->arg_types, guint8, i, arg_type);
4684 * mono_remoting_invoke:
4685 * @real_proxy: pointer to a RealProxy object
4686 * @msg: The MonoMethodMessage to execute
4687 * @exc: used to store exceptions
4688 * @out_args: used to store output arguments
4690 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
4691 * IMessage interface and it is not trivial to extract results from there. So
4692 * we call an helper method PrivateInvoke instead of calling
4693 * RealProxy::Invoke() directly.
4695 * Returns: the result object.
4698 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
4699 MonoObject **exc, MonoArray **out_args)
4701 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
4704 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
4707 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
4709 real_proxy->vtable->domain->private_invoke_method = im;
4712 pa [0] = real_proxy;
4717 return mono_runtime_invoke (im, NULL, pa, exc);
4721 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
4722 MonoObject **exc, MonoArray **out_args)
4724 static MonoClass *object_array_klass;
4727 MonoMethodSignature *sig;
4729 int i, j, outarg_count = 0;
4731 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
4733 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
4734 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
4735 target = tp->rp->unwrapped_server;
4737 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
4741 domain = mono_domain_get ();
4742 method = msg->method->method;
4743 sig = mono_method_signature (method);
4745 for (i = 0; i < sig->param_count; i++) {
4746 if (sig->params [i]->byref)
4750 if (!object_array_klass) {
4753 klass = mono_array_class_get (mono_defaults.object_class, 1);
4756 mono_memory_barrier ();
4757 object_array_klass = klass;
4760 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
4761 *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
4764 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
4766 for (i = 0, j = 0; i < sig->param_count; i++) {
4767 if (sig->params [i]->byref) {
4769 arg = mono_array_get (msg->args, gpointer, i);
4770 mono_array_setref (*out_args, j, arg);
4779 * mono_print_unhandled_exception:
4780 * @exc: The exception
4782 * Prints the unhandled exception.
4785 mono_print_unhandled_exception (MonoObject *exc)
4787 char *message = (char *) "";
4791 gboolean free_message = FALSE;
4793 if (mono_object_isinst (exc, mono_defaults.exception_class)) {
4794 klass = exc->vtable->klass;
4796 while (klass && method == NULL) {
4797 method = mono_class_get_method_from_name_flags (klass, "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
4799 klass = klass->parent;
4804 str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL);
4806 message = mono_string_to_utf8 (str);
4807 free_message = TRUE;
4812 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
4813 * exc->vtable->klass->name, message);
4815 g_printerr ("\nUnhandled Exception: %s\n", message);
4822 * mono_delegate_ctor:
4823 * @this: pointer to an uninitialized delegate object
4824 * @target: target object
4825 * @addr: pointer to native code
4828 * Initialize a delegate and sets a specific method, not the one
4829 * associated with addr. This is useful when sharing generic code.
4830 * In that case addr will most probably not be associated with the
4831 * correct instantiation of the method.
4834 mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer addr, MonoMethod *method)
4836 MonoDelegate *delegate = (MonoDelegate *)this;
4843 delegate->method = method;
4845 class = this->vtable->klass;
4846 mono_stats.delegate_creations++;
4848 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
4850 method = mono_marshal_get_remoting_invoke (method);
4851 delegate->method_ptr = mono_compile_method (method);
4852 MONO_OBJECT_SETREF (delegate, target, target);
4853 } else if (mono_method_signature (method)->hasthis && method->klass->valuetype) {
4854 method = mono_marshal_get_unbox_wrapper (method);
4855 delegate->method_ptr = mono_compile_method (method);
4856 MONO_OBJECT_SETREF (delegate, target, target);
4858 delegate->method_ptr = addr;
4859 MONO_OBJECT_SETREF (delegate, target, target);
4862 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->klass);
4866 * mono_delegate_ctor:
4867 * @this: pointer to an uninitialized delegate object
4868 * @target: target object
4869 * @addr: pointer to native code
4871 * This is used to initialize a delegate.
4874 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
4876 MonoDomain *domain = mono_domain_get ();
4878 MonoMethod *method = NULL;
4882 if ((ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr)))) {
4883 method = ji->method;
4884 g_assert (!method->klass->generic_container);
4887 mono_delegate_ctor_with_method (this, target, addr, method);
4891 * mono_method_call_message_new:
4892 * @method: method to encapsulate
4893 * @params: parameters to the method
4894 * @invoke: optional, delegate invoke.
4895 * @cb: async callback delegate.
4896 * @state: state passed to the async callback.
4898 * Translates arguments pointers into a MonoMethodMessage.
4901 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
4902 MonoDelegate **cb, MonoObject **state)
4904 MonoDomain *domain = mono_domain_get ();
4905 MonoMethodSignature *sig = mono_method_signature (method);
4906 MonoMethodMessage *msg;
4909 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
4912 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
4913 count = sig->param_count - 2;
4915 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
4916 count = sig->param_count;
4919 for (i = 0; i < count; i++) {
4924 if (sig->params [i]->byref)
4925 vpos = *((gpointer *)params [i]);
4929 type = sig->params [i]->type;
4930 class = mono_class_from_mono_type (sig->params [i]);
4932 if (class->valuetype)
4933 arg = mono_value_box (domain, class, vpos);
4935 arg = *((MonoObject **)vpos);
4937 mono_array_setref (msg->args, i, arg);
4940 if (cb != NULL && state != NULL) {
4941 *cb = *((MonoDelegate **)params [i]);
4943 *state = *((MonoObject **)params [i]);
4950 * mono_method_return_message_restore:
4952 * Restore results from message based processing back to arguments pointers
4955 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
4957 MonoMethodSignature *sig = mono_method_signature (method);
4958 int i, j, type, size, out_len;
4960 if (out_args == NULL)
4962 out_len = mono_array_length (out_args);
4966 for (i = 0, j = 0; i < sig->param_count; i++) {
4967 MonoType *pt = sig->params [i];
4972 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
4974 arg = mono_array_get (out_args, gpointer, j);
4978 case MONO_TYPE_VOID:
4979 g_assert_not_reached ();
4983 case MONO_TYPE_BOOLEAN:
4986 case MONO_TYPE_CHAR:
4993 case MONO_TYPE_VALUETYPE: {
4995 size = mono_class_value_size (((MonoObject*)arg)->vtable->klass, NULL);
4996 memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
4999 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
5000 memset (*((gpointer *)params [i]), 0, size);
5004 case MONO_TYPE_STRING:
5005 case MONO_TYPE_CLASS:
5006 case MONO_TYPE_ARRAY:
5007 case MONO_TYPE_SZARRAY:
5008 case MONO_TYPE_OBJECT:
5009 **((MonoObject ***)params [i]) = (MonoObject *)arg;
5012 g_assert_not_reached ();
5021 * mono_load_remote_field:
5022 * @this: pointer to an object
5023 * @klass: klass of the object containing @field
5024 * @field: the field to load
5025 * @res: a storage to store the result
5027 * This method is called by the runtime on attempts to load fields of
5028 * transparent proxy objects. @this points to such TP, @klass is the class of
5029 * the object containing @field. @res is a storage location which can be
5030 * used to store the result.
5032 * Returns: an address pointing to the value of field.
5035 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
5037 static MonoMethod *getter = NULL;
5038 MonoDomain *domain = mono_domain_get ();
5039 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5040 MonoClass *field_class;
5041 MonoMethodMessage *msg;
5042 MonoArray *out_args;
5046 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5047 g_assert (res != NULL);
5049 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5050 mono_field_get_value (tp->rp->unwrapped_server, field, res);
5055 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
5059 field_class = mono_class_from_mono_type (field->type);
5061 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5062 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
5063 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
5065 full_name = mono_type_get_full_name (klass);
5066 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5067 mono_array_setref (msg->args, 1, mono_string_new (domain, field->name));
5070 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5072 if (exc) mono_raise_exception ((MonoException *)exc);
5074 if (mono_array_length (out_args) == 0)
5077 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
5079 if (field_class->valuetype) {
5080 return ((char *)*res) + sizeof (MonoObject);
5086 * mono_load_remote_field_new:
5091 * Missing documentation.
5094 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
5096 static MonoMethod *getter = NULL;
5097 MonoDomain *domain = mono_domain_get ();
5098 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5099 MonoClass *field_class;
5100 MonoMethodMessage *msg;
5101 MonoArray *out_args;
5102 MonoObject *exc, *res;
5105 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5107 field_class = mono_class_from_mono_type (field->type);
5109 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5111 if (field_class->valuetype) {
5112 res = mono_object_new (domain, field_class);
5113 val = ((gchar *) res) + sizeof (MonoObject);
5117 mono_field_get_value (tp->rp->unwrapped_server, field, val);
5122 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
5126 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5127 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
5129 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
5131 full_name = mono_type_get_full_name (klass);
5132 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5133 mono_array_setref (msg->args, 1, mono_string_new (domain, field->name));
5136 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5138 if (exc) mono_raise_exception ((MonoException *)exc);
5140 if (mono_array_length (out_args) == 0)
5143 res = mono_array_get (out_args, MonoObject *, 0);
5149 * mono_store_remote_field:
5150 * @this: pointer to an object
5151 * @klass: klass of the object containing @field
5152 * @field: the field to load
5153 * @val: the value/object to store
5155 * This method is called by the runtime on attempts to store fields of
5156 * transparent proxy objects. @this points to such TP, @klass is the class of
5157 * the object containing @field. @val is the new value to store in @field.
5160 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
5162 static MonoMethod *setter = NULL;
5163 MonoDomain *domain = mono_domain_get ();
5164 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5165 MonoClass *field_class;
5166 MonoMethodMessage *msg;
5167 MonoArray *out_args;
5172 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5174 field_class = mono_class_from_mono_type (field->type);
5176 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5177 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
5178 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
5183 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
5187 if (field_class->valuetype)
5188 arg = mono_value_box (domain, field_class, val);
5190 arg = *((MonoObject **)val);
5193 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5194 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
5196 full_name = mono_type_get_full_name (klass);
5197 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5198 mono_array_setref (msg->args, 1, mono_string_new (domain, field->name));
5199 mono_array_setref (msg->args, 2, arg);
5202 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5204 if (exc) mono_raise_exception ((MonoException *)exc);
5208 * mono_store_remote_field_new:
5214 * Missing documentation
5217 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
5219 static MonoMethod *setter = NULL;
5220 MonoDomain *domain = mono_domain_get ();
5221 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5222 MonoClass *field_class;
5223 MonoMethodMessage *msg;
5224 MonoArray *out_args;
5228 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5230 field_class = mono_class_from_mono_type (field->type);
5232 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5233 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
5234 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
5239 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
5243 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5244 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
5246 full_name = mono_type_get_full_name (klass);
5247 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5248 mono_array_setref (msg->args, 1, mono_string_new (domain, field->name));
5249 mono_array_setref (msg->args, 2, arg);
5252 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5254 if (exc) mono_raise_exception ((MonoException *)exc);
5258 * mono_create_ftnptr:
5260 * Given a function address, create a function descriptor for it.
5261 * This is only needed on IA64 and PPC64.
5264 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
5269 mono_domain_lock (domain);
5270 desc = mono_code_manager_reserve (domain->code_mp, 2 * sizeof (gpointer));
5271 mono_domain_unlock (domain);
5277 #elif defined(__ppc64__) || defined(__powerpc64__)
5280 mono_domain_lock (domain);
5281 desc = mono_code_manager_reserve (domain->code_mp, 3 * sizeof (gpointer));
5282 mono_domain_unlock (domain);
5295 * mono_get_addr_from_ftnptr:
5297 * Given a pointer to a function descriptor, return the function address.
5298 * This is only needed on IA64 and PPC64.
5301 mono_get_addr_from_ftnptr (gpointer descr)
5303 #if defined(__ia64__) || defined(__ppc64__) || defined(__powerpc64__)
5304 return *(gpointer*)descr;
5312 * mono_string_chars:
5315 * Returns a pointer to the UCS16 characters stored in the MonoString
5318 mono_string_chars(MonoString *s)
5320 /* This method is here only for documentation extraction, this is a macro */
5324 * mono_string_length:
5327 * Returns the lenght in characters of the string
5330 mono_string_length (MonoString *s)
5332 /* This method is here only for documentation extraction, this is a macro */